Übungen
Am Ende der Seite finden Sie den Link zu den Lösungen.
Kapitel 2
1) Erstellen Sie ein Programm, das die Summe von 3.5 und 7.8 berechnet. Das Endergebnis soll über die Konsole ausgegeben werden.
Tipp: Fließkommazahlen lassen sich mit dem Datentyp double anlegen.
Kapitel 3
1) Erstellen Sie ein Programm, das die Fakultät der Zahl 7 berechnet und auf der Konsole ausgibt.
Hinweis: Die Fakultät einer positiven Ganzzahl n ist definiert als 1 * 2 * 3 * … * (n-1) * n. Die Fakultät von 0 beträgt 1, die Fakultät von negativen Zahlen und nicht ganzen Zahlen ist nicht definiert.
Kapitel 4
1) Ändern Sie das Programm von Übung 3.1 so ab, dass über eine Methode „fak“ die Fakultät einer beliebigen ganzen Zahl berechnet werden kann. Die Methode soll als Parameter die ganze Zahl erhalten, deren Fakultät berechnet werden soll. Sofern ein ungültiger (d.h. negativer) Wert an die Methode übergeben wird, soll 0 von der Methode zurück gegeben werden. Testen Sie Ihre Methode, indem Sie nacheinander die Fakultäten von 5 und 10 berechnen.
2) Erstellen Sie eine Klasse „Auto“. Ein Auto soll über die folgenden Eigenschaften verfügen: Kilometerstand als Fließkommazahl, Tankfüllung in Litern als Fließkommazahl sowie der Verbrauch pro 100 Kilometer als Fließkommazahl.
Wenn eine neue Instanz von „Auto“ erstellt wird, sollen Kilometerstand und Tankfüllung auf 0 stehen, der Verbrauch pro 100 Kilometer soll für jede Instanz individuell festgelegt werden können (d.h. über einen Konstruktorparameter).
Das Auto soll zwei Aktionen ausführen können: aufgetankt werden und fahren.
Auftanken: Es soll bei jedem Auftankvorgang festgelegt werden können, wieviel Liter getankt werden. Die maximale Tankfüllung soll 60 Liter betragen, d.h. wenn der Gesamtinhalt des Tankes durch einen Auftankvorgang diese Grenze überschreiten würde, soll der Auftankvorgang unterbrochen werden, wenn die Grenze erreicht ist. Am Ende jedes Auftankvorgangs soll der Gesamtstand des Tankes ausgegeben in der Form:
Neuer Füllstand des Tankes nach Auftanken: xyz Liter
Zudem soll die Tanken-Methode die tatsächlich getankte Menge an Benzin zurückgeben.
Fahren: Für jeden Fahrvorgang soll die Länge der zurückzulegenden Strecke in Kilometern angegeben werden. Das Auto soll sich um die angegebene Strecke bewegen, d.h. der Kilometerstand soll entsprechend angepasst werden und auch der Füllstand des Tankes soll gemäß des individuell festgelegten Verbrauchs und der zurückzulegenden Strecke verringert werden.
Sofern der Füllstand des Tankes nicht ausreicht, um die gesamte Strecke zurück zu legen, soll das Auto nur so weit bewegt werden, bis der Tankstand genau 0 Liter erreicht. Nach jedem Fahren soll folgende Ausgabe gemacht werden:
Tatsächlich zurückgelegte Kilometer: XX
Neuer Kilometerstand: XX
Neuer Füllstand des Tanks: XX Liter
Probieren Sie Ihre Klasse direkt aus, z.B. indem Sie z.B. ein Auto mit einem Verbrauch von 6 Liter pro 100 km erstellen und dort 60 Liter auftanken. Fahren Sie danach verschieden lange Strecken, z.B. 200, 300, 400 und wieder 200. Beim letzten Fahrvorgang dürfte das Auto statt der gewünschten 200 Kilometer nur noch 100 zurück legen, da dann der Tank nach 1000 gefahrenen Kilometern komplett entleert ist.
Hinweis: Um mehrere Informationen auf einmal auf der Konsole ausgeben zu können, können Sie diese durch den Plus-Operator verknüpfen, z.B. System.out.println(„Zuerst ein Text “ + 13 + “ dann eine Zahl.“). Dadurch wird folgende Ausgabe erzeugt:
Zuerst ein Text 13 dann eine Zahl.
Sollen mehrere Zeilen ausgegeben, rufen Sie System.out.println() jeweils einmal pro Zeile auf.
Kapitel 5
1) In Übung 4.1 haben Sie eine Methode erstellt, die die Fakultät einer ganzen Zahl berechnet. Bis zu welcher Eingabe errechnet die Methode das richtige Ergebnis? (denken Sie an den Überlauf, der bei zu großen Zahlen auftritt.) Finden Sie die größtmögliche Eingabe, indem Sie die Methode mit verschiedenen Eingaben testen. (Hinweis: Testen Sie die Methode mit den Eingaben 10 bis 20 und überprüfen Sie das jeweils gelieferte Ergebnis mit einem Taschenrechner oder Google. Um die Fakultät von 10 herauszufinden, geben Sie im Suchfeld von Google 10! ein.)
Wie können Sie die Methode abändern, sodass Sie auch bei größeren Eingabewerten noch korrekte Ergebnisse ausgibt?
2) Schreiben Sie eine Methode „floatingEquality“, die zwei Gleitkommazahlen auf Gleichheit prüft, dabei jedoch eine Toleranz von 0,001 erlaubt (d.h. wenn sich die beiden Zahlen maximal um 0,001 unterscheiden sollen sie als gleich angesehen werden).
Hinweis: Um den Betrag einer Zahl berechnen zu können, gibt es die Funtion Math.abs():
System.out.println(Math.abs(-22));
Diese Code-Zeile erzeugt die Ausgabe „22“.
3) Schreiben Sie eine Methode „charToAscii“, die für einen übergebenen chart-Wert den ASCII-Code des Zeichens bestimmt.
4) Schreiben Sie eine Methode „asciiToChar“, die einen int-Wert als ASCII-Code interpretiert und das entsprechende Zeichen zurück gibt.
Kapitel 6
1) Schreiben Sie eine Methode „floatingDivision“, die zwei int-Werte als Argumente nimmt und eine Division argument1 / argument2 durchführt. Das Ergebnis soll jedoch als korrekte Gleitkommazahl (float oder double) zurück gegeben werden (d.h. wenn Sie als Argumente die int-Werte 7 und 2 an die Methode übergeben, soll das korrekte Ergebnis 3.5 zurück gegeben werden und nicht das Ergebnis 3 der einfachen int-Division.)
2) Schreiben Sie eine Methode „simpleBoolDecider“, die zwei double-Werte als Argumente annimmt und einen boolschen Wert zurück liefert. Wenn arg1 < 5 ist soll die Methode false als Ergebnis liefern. Zudem soll auch false als Ergebnis geliefert werden, wenn die Summe von arg1 und arg2 größer als 100 ist. In allen anderen Fällen soll die Methode true als Ergebnis liefern. 3) Schreiben Sie eine Methode „simpleBoolDecider2“, die zwei double-Werte als Argumente annimmt und einen boolschen Wert zurück liefert. Die Methode soll genau dann true als Ergebnis liefern, wenn arg1 > arg2 ist und wenn gleichzeitig die Methode simpleBoolDecider aus Übung 6.2 für die übergebenden Argumente true liefert. In allen anderen Fällen soll die Methode false als Ergebnis liefern.
4) Schreiben Sie eine Methode „maximumSum“ die einen int-Wert als Argument nimmt und einen int-Wert zurück gibt. Für nicht-positive Eingaben soll die Methode direkt 0 als Ergebnis liefern. Bei positiven Eingaben soll so lange eine Aufsummierung der natürlichen Zahlen vorgenommen werden (d.h. 1 + 2 + 3 + …) bis die Summe den als Parameter übergebenen Wert erreicht oder überschreitet.
Zurückgegeben werden soll der letzte Summenwert, der kleiner als der übergebene int-Wert ist. (Beispiel: maximumSum wird mit dem Argument 9 aufgerufen. Dann soll als Ergebnis 6 zurück gegeben werden, weil 1 + 2 + 3 = 6 und damit noch kleiner als 9 ist, 1 + 2 + 3 + 4 = 10 jedoch bereits größer als 9 ist. 6 ist damit der letzte Summenwert, der noch kleiner als 9 ist.)
Kapitel 7
1) Schreiben Sie eine Methode „arraySum“, die als Argument ein Array von int-Werten übergeben bekommt und die Summe der in dem Array enthaltenen Werte berechnet und zurück gibt.
2) Schreiben Sie eine Methode „arraySumTwist“, die als Argument ein Array von int-Werten bekommt und die die Summe der in dem Array enthaltenen Werte, die größer als 10 sind, berechnet und zurück gibt. Alle Elemente des Arrays, die nicht größer als 10 sind, sollen bei der Summenberechnung ignoriert werden.
Hinweis: Sie müssen an der Lösung von Übung 7.1 nur eine Zeile ändern, wenn Sie den in Kapitel 6 eingeführten Fragezeichen-Operator ?: einsetzen.
3) Schreiben Sie eine Methode „arrayDeterminante“, die ein zweidimensionales int-Array als Argument übergeben bekommt und einen int-Wert zurück liefert. Das zweidimensionale Array soll genau die Ausmaße 2 x 2 haben, d.h. es soll genau aus zwei Sub-Arrays bestehen, die jeweils genau zwei Elemente besitzen. Wenn das übergebene Array nicht genau diese Ausmaße hat, soll direkt 0 als Ergebnis geliefert werden.
Hat das Array die geforderten Ausmaße, soll es als 2 x 2 Matrix interpretiert werden und die Determinante der Matrix soll berechnet und zurück gegeben werden.
Hinweis: Für eine 2 x 2 Matrix berechnet sich die Determinante nach folgender Formel:
Matrix M:
a1 a2
b1 b2
Determinante det(M) = a1 * b2 – a2 * b1
Kapitel 8
1) Schreiben Sie eine Methode „stringKonkat“, die als Argument ein Array von Strings übergeben bekommt. Als Ergebnis soll ein String zurückgegeben werden, der die Konkatenation (d.h. Aneinanderreihung) aller Strings aus dem Eingabe-Array enthält.
2) Schreiben Sie eine Methode „stringSum“, die als Eingabeparameter zwei Strings enthält und einen int-Wert zurück gibt. In den Strings sollen jeweils ganze Zahlen enthalten sein (also z.B. String arg1 = „5“;). Berechnen Sie die Summe der in den Strings enthaltenen Zahlen und geben sie als int-Wert zurück.
Kapitel 9
1) Ändern Sie die Klasse „Auto“ aus Übung 4.2 folgendermaßen ab:
– Die maximale Füllmenge soll nicht mehr pauschal 60 Liter betragen, sondern in einem neuen Attribut innerhalb der Klasse gespeichert werden. Das Attribut soll beim Konstruktoraufruf festgelegt werden (d.h. der Konstruktor benötigt einen zusätzlichen Parameter) und danach nicht mehr geändert werden können.
– Schreiben Sie 4 getter-Methoden für die Attribute (d.h. Füllmenge, maximale Füllmenge, Kilometerstand und Verbrauch).
– Erweitern Sie die Klasse um eine öffentliche Methode „benzinKlauen“ die als Argument eine Gleitkommazahl übergeben bekommt, die angibt, wieviel Liter Benzin geklaut werden sollen. Die intern gespeicherte Füllmenge soll entsprechend der geklauten Benzinmenge angepasst werden. Achten Sie darauf, dass nicht mehr Benzin geklaut werden kann, als sich im Tank befindet. Die Methode „benzinKlauen“ soll eine Gleitkommazahl zurück geben, die angibt, wieviel Benzin tatsächlich entwendet wurde.
– Führen Sie zwei weitere Attribute ein: ein String-Attribut, das den Namen des aktuellen Fahrers angibt sowie ein int-Attribut, das das Alter des aktuellen Fahrers angibt. Schreiben Sie für die beiden neuen Attribute jeweils einer getter-Methode. Zudem soll eine einzelne setter-Methode geschrieben werden, mit der beide Attribute auf einmal geändert werden (d.h. die setter-Methode erhält neuen Namen und das Alter des neuen Fahrers als Argumente). Achten Sie darauf, dass der Fahrer nur geändert werden kann, wenn das Alter des neuen Fahrers mindestens 18 (Jahre) beträgt.
2) Erweitern Sie das Programm aus Übung 9.1. Erstellen Sie eine neue Klasse „Tankstelle“. Die Klasse soll ein einzelnes (Gleitkomma-) Attribut besitzen, das den Preis pro Liter Benzin angibt. Das Attribut soll über einen Konstruktor-Parameter initialisiert werden, es soll über eine getter-Methode später gelesen werden können. Zudem soll es über eine setter-Methode verändert werden können, jedoch darf es niemals weniger als 0.5 (Euro / Liter) und niemals mehr als 2.5 (Euro / Liter) betragen.
Die Klasse soll eine Methode „autoAuftanken“ besitzen. Die Methode erhält als Parameter eine Referenz auf ein „Auto“-Objekt sowie eine Gleitkommazahl, die die gewünschte Tankmenge angibt. Innerhalb der Methode soll das „Auto“-Objekt gemäß der gewünschten Tankmenge aufgetankt werden. Die Methode soll einen Gleitkommawert zurück geben, der den Gesamtpreis für den Auftankvorgang angibt.
Kapitel 10
1) In einer Hauptmethode „hauptmethodeInt“ wird ein (beliebiger) int-Wert in einer Variablen „a1“ angelegt. Der int-Wert wird an eine von Ihnen zu erstellende Methode „hilfsmethodeInt“ übergeben. In der „hilfsmethodeInt“ wird der übergebene int-Wert verdoppelt. Nach Beendigung der Ausführung der „hilfsmethodeInt“ soll der verdoppelte Wert auch in der Variablen „a1“ innerhalb der „hauptmethodeInt“ gespeichert sein. Die Berechnung darf jedoch ausschließlich innerhalb der „hilfsmethodeInt“ ausgeführt werden, nicht direkt innerhalb der „hauptmethodeInt“.
Schreiben Sie „hauptmethodeInt“ und „hilfsmethodeInt“.
2) Verwenden Sie die Klasse „Auto“ aus Übung 9.1. Schreiben Sie eine Methode „autosAngleichen“, die zwei „Auto“-Instanzen auto1 und auto2 übergeben bekommt und keine Rückgabe tätigt. Innerhalb der Methode sollen die beiden Auto-Objekte aneinander angeglichen werden:
– Für auto2 soll derselbe Fahrer gesetzt werden, der bereits bei auto1 hinterlegt ist.
– Wenn beide Autos einen unterschiedlichen Füllstand haben, soll aus dem Auto mit höherem Füllstand soviel Benzin geklaut werden, bis es exakt denselben Füllstand hat wie das Auto mit dem niedrigeren Füllstand.
Prüfen Sie auch, ob es sich bei den übergebenen Instanzen für auto1 und auto2 nicht um null-Referencen handelt. Wenn mindestens eines der beiden Argumente eine null-Referenz ist, soll keine Aktion ausgeführt werden und die Methode direkt beendet werden.
Hinweis: Bei einer „void“-Methode (d.h. einer Methode die keinen Wert zurück gibt) können Sie das return-Statement ohne Parameter verwenden um die Ausführung einer Methode vorzeitig zu beenden. (d.h. Sie schreiben „return;“).
3) Die Aufgabe ist dieselbe wie in Übung 10.2. Allerdings soll nun nicht beim Angleichen der Autos Benzin aus dem volleren Tank geklaut werden, sondern der Tank mit niedrigerem Füllstand soll stattdessen aufgetankt werden, bis beide Autos denselben Füllstand haben.
4) Bonusfrage: Welches Problem ergibt sich (in manchen Fällen), wenn man die Autos durch zusätzliches Auftanken beim leereren Auto angleicht? Was kann man tun, um die Autos in diesen Fällen dennoch korrekt anzugleichen, ohne generell wie in 10.2 das vollere Auto zu beklauen?
Kapitel 11
1) Erweitern Sie die Klasse „Auto“ aus Übung 9.1 um eine equals-Methode. Zwei Autos sollen dabei dann als gleich angesehen werden, wenn sie denselben Füllstand, denselben maximalen Füllstand, denselben Kilometerstand und denselben Verbrauch haben. Wenn unterschiedliche Fahrer gesetzt sind soll dies jedoch keinen Einfluss auf das Ergebnis der Gleichheitsprüfung haben.
2) In dieser Übung sollen Sie eine einfache Nahrungskette im Tierreich implementieren.
Zunächst benötigen Sie eine abstrakte Basisklasse „Tier“. Es sollen drei Attribute vorhanden sein: ein (protected) Gleitkommawert, der das aktuelle Gewicht des Tieres angibt, ein privater Gleitkommawert, der das initiale Gewicht des Tieres angibt sowie eine (private) boolsche Variable, die angibt, ob das Tier lebendig oder tot ist.
Erstellen Sie einen Konstruktor für die abstrakte Klasse, der diese drei Attribute initialisiert: das Tier soll zu Beginn immer lebendig sein und das Gewicht sowie das initiale Gewicht soll über einen Konstruktor-Parameter angegeben werden (d.h. sowohl aktuelles als auch initiales Gewicht werden zunächst auf denselben Wert gesetzt, der dem Konstruktor übergeben wird). Wenn Sie später die einzelnen Unterklassen implementieren, sollen Sie im Konstruktor der Unterklassen jeweils den Konstruktor der abstrakten Basisklasse aufrufen.
Erstellen Sie öffentliche getter-Methoden für die drei Attribute.
Die Basisklasse „Tier“ soll eine abstrakte protected-Methode besitzen: die Methode „canEat“ soll eine Referenz auf ein Tier-Objekt übergeben bekommen und einen boolschen Wert zurück liefern. Denken Sie daran: da es sich um eine abstrakte Methode handelt, darf Sie in der Basisklasse noch nicht implementiert werden, sondern erst später in den konkreten Unterklassen. Mit der Methode soll später herausgefunden werden können, ob ein Tier ein anderes Tier fressen kann.
Außerdem soll die Klasse eine öffentliche Methode „wirdGetoetet“ beinhalten. Für diese Methode geben wir die Implementierung direkt in der Basisklasse an, es soll einfach das Attribut, das angibt ob das Tier lebendig ist, auf „false“ gesetzt werden.
Zudem soll die Basisklasse „Tier“ noch eine öffentliche Methode „eat“ besitzen: diese soll ebenfalls eine Referenz auf ein Tier-Objekt erhalten und keinen Rückgabewert besitzen. Diese Methode implementieren wir direkt in der Basisklasse. Der Sinn der Methode ist es, dass das als Argument übergebene Tier vom aktuellen Tier aufgefressen wird (d.h. tier1.eat(tier2) bedeutet, dass tier2 von tier1 aufgefressen wird).
Bei der Implementierung gehen Sie daher folgendermaßen vor: zunächst wird mit der Methode „canEat“ überprüft, ob das aktuelle Tier das übergebene Tier überhaupt fressen kann.
(Beachten Sie: „canEat“ haben wir in der Basisklasse „Tier“ noch garnicht implementiert, dennoch können wir die Methode bereits nutzen. Von der abstrakten Oberklasse „Tier“ können keine Instanzen erstellt werden, daher kann die Methode „eat“, die wiederum „canEat“ aufruft, noch nicht aufgerufen werden. Erst in den später zu erstellenden konkreten Unterklassen wird man „eat“ aufrufen können. Dort erstellen wir dann jedoch auch jeweils eine Implementierung für „canEat“, sodass bei der Ausführung von „eat“ dann jeweils die „canEat“ Methode der jeweiligen Unterklasse verwendet wird.)
Wenn das Tier nicht gefressen werden kann, beenden wir die Methodenausführung von „eat“ und führen keine weiteren Operationen aus. Wenn das übergebene Tier jedoch gefressen werden kann, addieren wir das Gewicht des gefressenen Tierers zum aktuellen Gewicht des fressenden Tieres und passen dessen aktuelles Gewicht dementsprechend an. Zudem rufen wir auf dem gefressenen Tier die Methode „wirdGetoetet“ auf, um zu signalisieren, dass das Tier jetzt tot ist.
Weiterhin erstellen wir eine öffentliche Methode „verdauen“. Diese Methode erhält keinen Parameter und hat auch keinen Rückgabewert. Stattdessen wird in dieser Methode lediglich das Gewicht des Tieres nach folgender Systematik verändert: wenn das aktuelle Gewicht nicht größer als das initiale Gewicht ist, wird keine Veränderung durchgeführt. Wenn das aktuelle Gewicht größer ist als das initiale Gewicht, wird das Gewicht um 95 % des „zusätzlichen“ Gewichtes reduziert.
(Beispiel: Das initiale Gewicht beträgt 50 (Gramm), das aktuelle Gewicht beträgt 150 (Gramm). Dann beträgt das zusätzliche Gewicht also 100 Gramm und dieses wird nun um 95 % reduziert. Dann bleiben lediglich 5 Gramm vom zusätzlichen Gewicht übrig, d.h. das neue aktuelle Gewicht beträgt 50 Gramm (Initialgewicht) + 5 Gramm (zusätzliches Gewicht) = 55 Gramm)
Das initiale Gewicht bleibt immer unverändert.
Nun erstellen wir konkrete Unterklassen von „Tier“, nämlich „Eichhoernchen“, „Baummarder“ und „Uhu“. Wir müssen also für jede dieser Unterklassen jeweils die Methode „canEat“ implementieren. Zudem müssen wir für jede dieser Unterklassen einen Konstruktor erstellen, der den Konstruktor der Basisklasse aufruft und Gewicht, initiales Gewicht und den „Lebendigkeitsstatus“ initialisiert.
Nachdem wir die Konstruktoren für alle drei Klassen angelegt haben, machen wir uns an die Implementierung der Methode „canEat“ für die 3 Klassen. Wir starten mit dem „Eichhoernchen“: dieses steht ganz unten in der Nahrungskette und kann daher keines der anderen Tiere fressen. Die Methode „canEat“ gibt daher immer „false“ zurück.
Der „Baummarder“ steht über dem Eichhoernchen in der Nahrungskette und kann ein lebendiges Eichhoernchen also auffressen. Die Methode „canEat“ soll also beim „Baummarder“ genau dann „true“ zurückgeben, wenn das als Parameter übergebene Tier ein „Eichhoernchen“ ist und wenn beide Tiere noch lebendig sind. In allen anderen Fällen soll die Methode false zurück geben.
Der „Uhu“ steht an der Spitze der Nahrungskette, er kann sowohl „Eichhoernchen“ als auch „Baummarder“ fressen. Die Methode „canEat“ soll beim „Uhu“ also genau dann „true“ zurück geben, wenn entweder ein „Eichhoernchen“ oder ein „Baummarder“ als Parameter übergeben wird und wenn beide Tiere noch lebendig sind.
Wir können den Subklassen nun noch beliebige weitere Methoden hinzufügen. Beispielhaft fügen wir dem „Uhu“ eine Methode „fliegen“ hinzu (keine Übergabeparameter, kein Rückgabewert). Einziger Effekt soll eine Reduktion des Gewichtes um 10 (Gramm) sein, jedoch nur bis zur Untergrenze des Initialgewichtes.
Erstellen Sie nun einige Instanzen und probieren aus, ob das Verhalten Ihrer Klassen dem erwarteten Verhalten entspricht. Sie können dazu z.B. nach jeder Operation Gewicht und Lebendigkeitsstatus eines Objektes überprüfen und mittels „System.out.println()“ über die Konsole ausgeben.
Kapitel 12
1) Erstellen Sie eine Methode „division“, die eine Division von zwei int-Werten durchführt. Führen Sie damit eine Division durch 0 aus und starten Sie das Programm. Das Programm sollte durch das Auftreten einer Exception abstürzen und eine Fehlermeldung ausgeben. Finden Sie mit Hilfe der Fehlermeldung heraus, welche Exception ausgelöst wird und ändern Sie die Methode „division“ so ab, dass diese Exception abgefangen wird. Es soll eine hilfreiche Hinweismeldung ausgegeben werden (System.out.println()) und als Ergebnis 0 zurück geliefert werden.
2) In Übung 4.1 haben Sie eine Methode „fak“ erstellt, die die Fakultät einer natürlichen Zahl berechnet. Wenn eine negative Zahl angegeben wurde, lieferte die Methode ursprünglich 0 als Resultat. Tatsächlich sind Fakultäten von negativen Zahlen jedoch nicht definiert. Ändern Sie die Methode so ab, dass nun stattdessen eine „IllegalArgumentException“ mit einem hilfreichen Hinweistext ausgelöst wird, wenn eine negative Zahl als Parameter verwendet wird. Rufen Sie die Methode innerhalb einer „main“-Hauptmethode auf und fangen Sie die Exception dort ab und geben den Hinweistext aus.
Kapitel 13
1) Erstellen Sie eine generische Klasse „Arena“, die zwei Typparameter (T und V) nimmt, die beide jeweils mit einer Unterklasse von „Tier“ aus Übung 11.2 belegt werden müssen. In der Arena treten die Tiere nun gegeneinander an. Die Klasse soll eine einzelne Methode „showdown“ besitzen, die einen Parameter vom Typ T und einem vom Typ V erhält (d.h. zwei Instanzen von (möglicherweise unterschiedlichen) Subklassen von „Tier“). Als Resultat soll ein Objekt vom Typ „Tier“ zurück gegeben werden.
Da zwei Tiere übergeben wurden, soll dasjenige (Tier-)Objekt zurückgegeben werden, das ein Zusammentreffen der beiden Tiere überlebt (d.h. wenn es einem Tier möglich ist, das andere zu fressen). Wenn beide Tiere das Zusammentreffen überleben, soll die null-Referenz zurückgegeben werden.
2) Führen Sie die gleiche Aufgabe wie in Übung 13.1 aus. Verwenden Sie dabei jedoch keine generische Klasse, sondern lediglich eine generische Methode „showdown“.
Kapitel 14
1) Erstellen Sie eine Methode „listCount“, die als Parameter eine ArrayList von String Elementen erhält und einen int-Wert zurück liefert. Der int-Wert soll die Anzahl der Elemente der Liste angeben, die mit einem großen „D“ starten.
Hinweis 1: Schauen Sie sich noch einmal die String-Operationen aus Kapitel 8.1 genau an.
Hinweis 2: Sie können die Elemente einer Liste mit der for-Schleife durchlaufen:
for (String element : listOfStrings)
{
System.out.println(element);
}
2) Erstellen Sie eine Methode „setInsert“, die als Parameter eine TreeSet von Integer-Elementen sowie einen einzelnen int-Wert „maxVal“ erhält. Die Methode soll keinen Wert zurückgeben und das folgende Verhalten aufweisen:
Beginnend mit 1 sollen so lange fortlaufende int-Werte, die noch nicht in der Menge enthalten sind, hinzugefügt werden, bis die Summe aller in der Menge enthaltenen Werte den gelieferten Parameter „maxVal“ überschreiten würden. Der Wert, der zur Überschreitung von maxVal führen würde, soll nicht mehr eingefügt werden. Sofern die Summe der in der Menge enthaltenen Werte bereits zu Beginn den „maxVal“ erreicht oder überschreitet, sollen keine weiteren Elemente eingefügt werden.
Beispiel: Die Menge enthält initial die Werte (2,3,4) und es wird 20 als „maxVal“ angegeben. Die initiale Summe der Werte der Menge beträgt 9, daher werden noch die Werte 1 und 5 hinzugefügt. Dann beträgt die Summe der Werte 15, durch das nachfolgende Einfügen von 6 würde der Maximalwert der Summe von 20 überschritten, daher werden keine weiteren Werte mehr eingefügt.
3) Erstellen Sie zunächst eine TreeMap
Hinweis: Schauen Sie sich nochmal die String-Operationen aus Kapitel 8.1 sowie die Konvertierungsmöglichkeiten aus Kapitel 8.2 an. Um ein einzelnes char-Zeichen in einen String zu konvertieren, können Sie die statische „Character“-Methode „toString“ verwenden: String str = Character.toString(char);
4) Bonusaufgabe: Können Sie Übung 14.3 auch lösen, ohne die Konvertierungsfunktionen zwischen int und String zu benutzen?
Tipp: Benutzern Sie den Divisionsoperator und den Restwertoperator für ganze Zahlen.
Hinweis zu den Übungen 1 – 4:
Die von Java bereitgestellten Collection-Klassen befinden sich innerhalb des Paketes java.util. Wenn Sie also eine Collection-Klasse verwenden wollen, müssen Sie sie über die „import“-Anweisung einbinden:
import java.util.*;
Kapitel 15
1) Mit der „writeInt“ Methode von RandomAccessFile können int-Werte in eine Datei geschrieben werden. (Und mit der „readInt“ Methode können diese int-Werte später wieder ausgelesen werden). Schreiben Sie eine Methode „writeList“, die als Parameter eine ArrayList von Integer-Werten erhält sowie einen String. Die Elemente der Liste sollen einzeln in die durch den String angegebene Datei geschrieben werden. Um die Zahlen später wieder auslesen zu können, schreiben Sie als ersten Wert die Länge der Liste in die Datei, erst danach folgen die eigentlichen Elemente.
2) Schreiben Sie die Methode „readInt“, um die Datei, die mittels der Methode „writeInt“ aus Übung 15.1 geschrieben wurde, wieder auszulesen. Die Methode soll als Parameter den Dateinamen der zu lesenden Datei erhalten und eine ArrayList von Integer-Werten zurück geben. Denken Sie daran, dass Sie zunächst die Länge der Liste auslesen und danach erst die eigentlichen Elemente.
Hinweis zu Übung 1 + 2:
Bei der Verwendung von bestimmten Klassen und Methoden „erzwingt“ Java die Verwendung von try-catch-Konstrukten. Das geschieht um sicher zu stellen, dass oft vorkommende Exceptions auf jeden Fall behandelt werden.
So ist es auch mit der Klasse „RandomAccessFile“. Um diese benutzen zu können, muss der Code innerhalb eines try-catch-Konstruktes gekapselt werden.
Kapseln Sie daher Ihren Code innerhalb der Methoden writeInt und readInt jeweils innerhalb des folgenden Konstruktes:
try {
// ihre Code hier ...
} catch (FileNotFoundException e) {
System.out.println("Datei wurde nicht gefunden");
} catch (IOException e) {
System.out.println("Fehler beim Lesen/Schreiben der Datei");
}
Sowohl die genannten Exceptions als auch die Klasse RandomAccessFile befinden sich innerhalb des Paketes java.io. Sie müssen das Paket also innerhalb Ihrer Quellcodedateien einbinden.
import java.io.*;
Kapitel 16
1) Schreiben Sie zunächst eine Funktion „berechneSumme“, die die Summe der ersten n ganzen Zahlen berechnet. Diese Methode wurde bereits in Kapitel 4.1 geschrieben, Sie können die Methode einfach von dort übernehmen.
Erstellen Sie nun zwei Threads, die diese Methode gleichzeitig ausführen. Gestalten Sie die Threads so, dass jeweils nach Beendigung der Berechnung eine Nachricht ausgegeben wird, z.B. „Thread 1 hat die Berechnung beendet und folgendes Ergebnis erhalten: 5050“. Führen Sie das erstellte Programm nun mehrmals aus und variieren dabei den Parameter n für die beiden Aufrufe von „berechneSumme“ in den beiden Threads.
z.B. 1. Aufruf 10 und 20 verwenden, 2. Aufruf 30000 und 20000 verwenden, 3. Aufruf 40000 und 40000 verwenden, 4. Aufruf 10 und 1000000 verwenden, usw. Beobachten Sie jeweils, welcher Thread als erstes seine Arbeit beendet hat. Insbesondere in den Fällen, in denen Sie die Methode in beiden Threads mit dem gleichen Parameter aufrufen sollte es relativ zufällig sein, welcher Thread seine Arbeit als erstes beendet.
2) Wir wollen nun die Klasse „Auto“ aus Übung 9.1 innerhalb von Threads verwenden. Wir erstellen dazu eine neue Klasse „SimultanAuftanken“. Die Klasse soll ein einzelnes privates Attribut „alleAutos“ besitzen, nämlich eine ArrayList bestehend aus „Auto“-Elementen. Das Attribut soll durch einen Parameter des Konstruktoraufrufes initialisiert werden. Initialisieren Sie das Attribut dabei auf folgende Weise innerhalb des Konstruktors:
public SimultanAuftanken(ArrayList autos)
{
alleAutos = new ArrayList();
for (int i = 0; i < autos.size(); ++i)
{
alleAutos.add(autos.get(i));
}
}
(Hinweis: Mit der Methode get von ArrayList kann man auf ein bestimmtes Element zugreifen. Angegeben wird wieder der nullbasierte Index, d.h. mit get(0) bekommt man das erste Element der Liste.)
Zudem erstellen wir eine private Methode "naechstesAuto", die keinen Parameter erhält und eine Referenz auf ein Auto-Objekt zurückgibt. Die Methode soll das erste Element aus der Liste mit den Autos auswählen, dieses aus der Liste entfernen und das Objekt zurückgeben. Wenn in der Liste kein Objekt enthalten ist, soll die null-Referenz zurückgegeben werden.
Nun erstellen wir eine Worker-Methode "workThread" für einen Thread (d.h. eine Methode, die den gesamten Code beinhaltet, den ein einzelner Thread später ausführen soll). Innerhalb dieser Methode, die weder Parameter noch Rückgabewert besitzt, soll in einer Schleife so lange die zuvor erstellen Methode "naechstesAuto" aufgerufen werden, bis diese die null-Referenz liefert (d.h. bis alle Autos, die in der Liste der Autos enthalten waren, abgearbeitet sind). In dieser Schleife soll jedes Auto-Element, das über den Aufruf von "naechstesAuto" zurückgeliefert wurde, mit Hilfe der "Auto"-Methode zum Auftanken wieder aufgetankt werden. Tanken Sie jeweils 50 (Liter).
Was wir also erreichen wollen: wir wollen unserer neuen Klasse eine Liste von Autos übergeben, und diese sollen nun nicht einzeln nacheinander, sondern simultan über Threads, betankt werden. Dazu fehlt nun noch das Erstellen und Starten der Threads.
Dazu erstellen wir eine öffentliche Methode "startThreads", die einen int-Parameter erhält und keinen Rückgabewert erhält. Der int-Parameter soll die Anzahl der Threads angeben. Erstellen Sie die Threads also in einer Schleife. Innerhalb der überschriebenen "run()"-Methode unserer Threads rufen wir jeweils nur die zuvor erstellte Methode "workThread()" auf. Wir starten jeden Thread direkt nachdem wir ihn angelegt haben.
Damit ist die Klasse nun fertig gestellt. Beim Konstruktoraufruf können wir eine Liste von Autos übergeben, die aufgetankt werden sollen. Sobald wir danach "startThreads" aufrufen werden die Autos parallel zueinander aufgetankt.
3) Wir testen nun unsere Klasse "SimultanAuftanken" aus der Übung 16.2. Erstellen Sie dazu folgende Hauptmethode:
public static void main(String[] args)
{
ArrayList meineAutos = new ArrayList();
for (int i = 0; i < 10000; ++i)
{
Auto neuesAuto = new Auto(6.0, 100);
// erster Parameter: Verbrauch,
// zweiter Parameter: maximaler Füllstand
meineAutos.add(neuesAuto);
}
SimultanAuftanken simultan =
new SimultanAuftanken(meineAutos);
simultan.startThreads(40);
// Hinweis: da alle Auftankvorgänge im Hintergrund in
// Threads ausgeführt werden, warten wir im
// Hauptthread zwei Sekunden, bis wir weiter machen.
// Bis dahin sollten alle Tankvorgänge auf jeden Fall
// abgeschlossen sein.
// Der Methode "Thread.sleep" kann man die zu pausierende
// Zeit in Millisekunden angeben, für diese
// Zeit "ruht" das Programm dann.
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
for (int i = 0; i < meineAutos.size(); ++i)
{
Auto dasAuto = meineAutos.get(i);
double fuellstand = dasAuto.getAktuellerFuellstand();
if (fuellstand != 50)
System.out.println("Füllstand von Auto " + i +
": " + fuellstand);
}
}
Wir würden erwarten, dass der Füllstand, der am Ende ausgegeben wird, bei allen Autos 50 (Liter) beträgt. Das ist aber nicht der Fall. Warum ist das so, und was müssen Sie an der Klasse "SimultanAuftanken" ändern, damit das Programm die zu erwartende Ausgabe erzeugt?
Kapitel 17
1) Ändern Sie das Server-Programm aus Kapitel 17.2 so ab, dass es nicht nach einer Verbindung mit einem Clienten beendet wird, sondern dass sich danach noch weitere Clienten verbinden können. Nach der Änderung sollten Sie das Client-Programm mehrmals starten können, ohne die Server-Anwendung ebenfalls neustarten zu müssen.
2) Schreiben Sie eine Methode "urlContains", die als Argumente zwei String-Parameter "url" und "search" erhält und deren Rückgabetyp boolean ist. Die Methode soll den Inhalt, der über die Internetadresse "url" abgerufen werden kann, auslesen und true zurück liefern, falls der Teilstring "search" innerhalb des Inhalts der Internetadresse gefunden werden kann, ansonsten false.
Hinweis: Kapseln Sie den Code der Methode urlContains abermals innerhalb eines try-catch-Konstruktes:
try
{
// Ihre Code hier ...
} catch (MalformedURLException e)
{
System.out.println("Sie haben eine ungültige URL angegeben.");
return ...
} catch (IOException e)
{
System.out.println("Fehler bei der Datenübertragung");
return ...
}
Hinweis zu den Übungen 1 und 2:
Die Klassen URL, URLConnection, Socket und ServerSocket sowie die Exception MalformedURLException sind Teil des Paketes java.net. Die Klassen InputStream und OutputStream sowie die Exception IOException sind Teil des Paketes java.io. Wenn Sie diese Klassen und Exceptions nutzen wollen, müssen Sie mit der "import"-Anweisung eingebunden werden.
import java.net.*;
import java.io.*;
Kapitel 18
1) Ändern Sie das Programm-Beispiel aus Kapitel 18 folgendermaßen ab:
Statt einem Eingabefeld soll es nun zwei Eingabefelder besitzen. Durch Klick auf den Button soll nun die Summe der Werte die in den Eingabefeldern enthalten sind berechnet werden und in das Ergebnislabel geschrieben werden.
2) Ändern Sie das die Klasse aus Übung 18.1 nochmals ab: nun sollen statt einem Button zwei Buttons enthalten sein, die mit "+" bzw. "-" beschriftet werden. Bei Klick auf den "+" Button soll weiterhin die Summe der beiden Zahlen in den Eingabefeldern berechnet werden, bei Klick auf "-" soll dagegen nun eine Subtraktion mit den Werten in den beiden Eingabefeldern berechnet werden und im Ergebnislabel ausgegeben werden.
Hinweise zu den Übungen 1 und 2:
Die einzelnen GUI-Elemente gehören zum Paket javax.swing. Das verwendete Layout gehört zum Paket java.awt. Die Klasse ActionListener gehört zur Klasse java.awt.event. Wenn Sie diese Klassen verwenden möchten, müssen Sie zunächst über die "import"-Anweisung eingebunden werden.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*
Beispiellösungen
Unsere Lösungsvorschläge können Sie auf der folgenden Seite herunter laden:
Ihr Feedback ist gefragt
Nun, da Sie am Ende des Tutorials angelangt sind, möchten wir auch gerne erfahren, ob Sie das Tutorial hilfreich fanden. Sie können uns auch mitteilen, was Sie nicht gut fanden, was wir noch verbessern können. Basierend auf dem Feedback wird das Tutorial von Zeit zu Zeit überarbeitet.
Bitte nehmen Sie sich deshalb 2 Minuten Zeit, um drei Fragen zu beantworten. Vielen Dank.
Feedback abgeben
Eine ausführliche Liste unserer Buchempfehlungen für Java finden Sie hier.
Java-Tutorial Kapitel:
1. Grundlagen: Compiler und Entwicklungsumgebung2. Kernelemente: Variablen und Ausdrücke
3. Ablaufsteuerung in Java
4. Überblick Objektorientierung
5. Primitive Datentypen
6. Ausdrücke und Operatoren
7. Arrays in Java
8. Zeichenketten
9. Klassen und Objekte
10. Referenzen und Parameter
11. Vererbung in Java
12. Exceptions
13. Generics
14. Collections
15. Dateiverarbeitung in Java
16. Nebenläufigkeit
17. Netzwerkprogrammierung
18. Grafische Oberflächen (GUIs)
19. Java-Webtipps
20. Code-Download und Übungen
Für den Zugriff auf die Kapitel 5 - 20 ist eine Registrierung notwendig.
Einloggen
Wenn Sie noch kein Benutzerkonto bei programmierenlernen24.de haben, müssen Sie sich zunächst registrieren, um vollen Zugriff auf unser Java-Tutorial zu bekommen.
Passwort vergessen? Lassen Sie sich hier ein neues zusenden.
Unsere Buchempfehlungen
Oder sehen Sie sich die vollständige Liste der Empfehlungen für Java an.Wir haben auch eine Empfehlung für einen Java-Fernkurs parat.