Wir wollen jetzt ein Programm schreiben, welches den Benzinverbrauch eines Autos simuliert. Unsere neue Klasse heißt demzufolge Auto.
Schritt 1 - Neue Klasse erzeugen
Erzeugen Sie eine neues leeres Projekt mit der Klasse Auto.
Doppelklicken Sie auf die Klasse Auto, um den Quelltext zu bearbeiten. Bereinigen Sie dann den Quelltext so, dass nur noch der Minimalquelltext übrig ist:
public class Auto { public Auto() { } }
Schritt 2 - das Auto kann fahren
Was soll unser Auto alles können? Ähnlich wie bei dem Waage-Projekt wollen wir uns zunächst Gedanken darüber machen, welche Methoden die Auto-Objekte benötigen, damit sie "fahren" können.
public void fahren(double km) { }
Das wäre ein erster Vorschlag für eine Methode zum Fahren. Wir geben beispielsweise den Wert 12.0 als Parameter an, und unser Auto legt eine Strecke von 12.0 km zurück. Natürlich muss diese Streckenveränderung irgendwo gespeichert werden, und damit kommen wir auch schon zum ersten Attribut unserer Klasse, dem Kilometerstand des Tachos.
public class Auto { double kmStand; public Auto() { kmStand = 100; } public void fahren(double km) { kmStand += km; } }
Geben Sie diesen Quelltext ein, kompilieren Sie ihn und erzeugen Sie dann ein Objekt auto1 der Klasse Auto. Rufen Sie dann die Methode fahren mit dem Wert 12.0 auf und inspizieren Sie das Objekt mit dem Objektinspektor:
Der Kilometerstand wurde aktualisiert
Das Attribut kmStand hat tatsächlich den Wert 12.0
Exkurs: Der += Operator und seine Verwandten
Im Quelltext der Methode fahren hätte man natürlich auch schreiben können:
kmStand = kmStand + km;
Eine Zuweisung, die den Wert einer Variable um eine bestimmte Zahl erhöht, nennt man Inkrementation. Eine solche Inkrementation kann man auch einfacher schreiben:
kmStand += km;
Diese kurze Anweisung mit dem += Operator besagt: Erhöhe den Wert der Variable kmStand um den Wert km.
Neben dem += Operator gibt es auch den -=, den *= und den /= Operator zum Subtrahieren, Multiplizieren und Dividieren von gegebenen Variablen.
Übungen
Übung 4.1-1
Ergänzen Sie den Quelltext der Klasse Auto um ein Attribut, das speichert, wie viel Liter Benzin noch im Tank des Autos verfügbar sind. Dabei gehen wir von folgenden Annahmen aus, die Sie mit berücksichtigen müssen:
Der Tank des Autos soll maximal 70 Liter Benzin fassen, und das Auto soll durchschnittlich 7.3 Liter pro 100 km Fahrstrecke verbrauchen.
In der Methode fahren() sollen nun für jeden gefahrenen Kilometer genau 0,073 Liter von dem vorhandenen Benzinvolumen abgezogen werden.
Schreiben Sie außerdem eine Methode anzeigen(), die mit Hilfe von System.out.println()-Anweisungen zwei Daten in der Konsole anzeigt:
- Den aktuellen Kilometerstand in km
- Den aktuellen Benzinvorrat in Litern
Die beiden Einheiten "km" und "Liter" müssen ebenfalls hinter den Zahlen zu sehen sein.
Lösungsvorschlag (nur für Lehrpersonen; Zugangsdaten erforderlich)
Übung 4.1-2
Bei der Übung 4.1-1 sind wir davon ausgegangen, dass der Tank des Autos maximal 70 Liter Benzin fasst. Es gibt aber auch Autos, deren Tank nur 50 Liter fasst; andere Autos wiederum können bis zu 80 oder 90 Litern betankt werden.
Verbessern Sie die Klasse Auto so, dass man beim Erzeugen eines neuen Auto-Objektes die Kapazität des Benzintanks mit angeben kann. Die per Parameter übergebene Kapazität muss dann natürlich in einem weiteren Attribut gespeichert werden, so dass auch andere Methoden auf diesen Wert zugreifen können.
Lösungsvorschlag (nur für Lehrpersonen; Zugangsdaten erforderlich)
Übung 4.1-3
Auch der Verbrauch des Autos soll nun beim Erzeugen der Auto-Objekte festgelegt werden können, denn nicht jedes Auto verbraucht im Schnitt 7.3 Liter/100 km. Ergänzen Sie die Klasse entsprechend.
Lösungsvorschlag (nur für Lehrpersonen; Zugangsdaten erforderlich)
Schritt 3 - Testklassen
Es ist Ihnen sicherlich auch schon aufgefallen, dass man beim Entwickeln einer Klasse diese recht häufig testen muss. Sobald man den Quelltext etwas verändert hat, muss man neu kompilieren, und alle Objekte, die man vorher angelegt hatte, sind wieder verschwunden. Also muss wieder ein neues Objekt erstellt werden, und alle Methoden müssen wieder aufgerufen werden. Oft haben diese Methoden mehrere Parameter, die dann auch noch eingetippt werden müssen.
All diese Arbeit kann man sich erleichtern, wenn man die Klasse - hier Auto - von einer Testklasse prüfen lässt. Hier der Quelltext einer solchen Testklasse für die Klasse Auto.
public class Test { Auto otto; public Test() { otto = new Auto(10000, 70, 7.5); otto.fahren(20); otto.anzeigen(); otto.fahren(60); otto.anzeigen(); otto.fahren(20); otto.anzeigen(); } }
Zuerst wird im Konstruktor der Testklasse ein Auto-Objekt otto initialisiert, und zwar ein Auto, das schon 10.000 km gefahren ist, ein Tankvolumen von 70 Litern hat und einen durchschnittlichen Verbrauch von 7.5 Litern / 100 km hat.
Anschließend fährt das Auto 20 km, danach werden die wichtigsten Attributwerte angezeigt, zum Beispiel der aktuelle Benzinverbrauch, der ja von der gefahrenen Strecke abhängt. Danach wird die fahren-Methode noch zweimal mit den Werten 60 und 20 aufgerufen, und jedes Mal werden die Attributwerte durch Ausführen der anzeigen-Methode überprüft.
Mithilfe dieser Testklasse und der Konsolenausgabe lässt sich leicht überprüfen, ob der Quelltext der zu entwickelnden Klasse wirklich das tut, was er soll.
Der Arbeitsaufwand für Sie selbst ist recht gering, nachdem Sie die Testklasse erst einmal fertiggestellt haben.
Es reicht, wenn Sie nach jeder Veränderung der Klasse Auto das Projekt kompilieren (ein Tastenbefehl) und dann ein Objekt der Testklasse erzeugen (ein Mausklick).
Da der gesamte Test bereits durch den Konstruktor der Testklasse durchgeführt wird, muss nach dem Erzeugen des Testklassen-Objekts auch keine weitere Methode mehr aufgerufen werden, um den eigentlichen Test durchzuführen.
Schritt 4 - Tanken
Wenn das Auto fährt, wird Benzin verbraucht, dafür haben Sie ja bereits gesorgt. Für jeden gefahrenen Kilometer wird 1/100 des angegebenen Verbrauchswerts (zum Beispiel 7,5 Liter / 100 km) von dem im Tank vorhandenen Benzinvolumen abgezogen. Wenn Ihr Auto viel fährt, ist der Tank aber irgendwann leer. Bereits bevor der Tank ganz leer ist, sollte man zu einer Tankstelle fahren und den Benzintank wieder füllen.
Übung 4.1-4
Erweitern Sie Ihre Klasse Auto so, dass das Auto wieder vollgetankt werden kann.
Stufe 1: Schreiben Sie eine Methode tanken() ohne Parameter, nach deren Aufruf das Auto wieder vollgetankt ist, also die aktuelle Benzinmenge der Tankkapazität entspricht.
Stufe 2: Schreiben Sie eine Methode tanken(double pVolumen), mit der Sie das Auto um ein bestimmtes Benzinvolumen betanken können, also beispielsweise mit 20 Litern, wenn Sie nicht genug Geld haben um das Auto vollzutanken.
Stufe 3: Erweitern Sie die Methode tanken(double pVolumen)so, dass der Tank nicht überlaufen kann. Mit der Methode nach Stufe 2 könnte man ja theoretisch 100 Liter tanken, obwohl der Tank vielleicht nur 70 Liter fasst. Sie müssen also mit einer if-else-Anweisung dafür sorgen, dass das Benzinvolumen im Tank nicht die Tankkapazität überschreitet.
Lösungsvorschlag (nur für Lehrpersonen; Zugangsdaten erforderlich)
Schritt 5 - Fahren
Wir wollen jetzt das Auto "richtig" fahren lassen. Den Graphikmodus von Java beherrschen wir noch nicht, darum müssen wir das Fahren in der Textkonsole simulieren. Schauen wir uns dazu noch einmal die Testklasse aus Schritt 3 an:
public class Test { Auto otto; public Test() { otto = new Auto(10000, 70, 7.5); otto.fahren(20); otto.anzeigen(); otto.fahren(60); otto.anzeigen(); otto.fahren(20); otto.anzeigen(); } }
Diesen Quelltext wollen wir jetzt radikal verändern, kürzen und dabei verbessern und gleicheitig etwas Neues lernen.
public class Test { Auto otto; public Test() { otto = new Auto(10000, 70, 7.5); while (!tankLeer()) { otto.fahren(10); otto.anzeigen(); } } }
Dieses Programm lässt das Auto jeweils 10 km fahren und dann den Kilometerstand und die vorhandene Benzinmenge anzeigen. Das Ganze wird solange wiederholt, bis der Tank leer ist. Um dies zu überprüfen, benötigt die Klasse eine Methode
public boolean tankLeer()
die den Wert true liefert, falls der Tank leer ist.
Das Fahren selbst wird von einer sogenannten While-Schleife übernommen. Schleifen haben wir bisher noch nicht in unserem Kurs gehabt, daher wollen wir uns jetzt etwas näher damit auseinandersetzen. Das machen wir aber auf der nächsten Seite dieser Folge 4. Hier wollen wir nur ganz kurz überlegen, wie eine solche Programmschleife arbeitet.
Programmschleifen
Erinnern Sie sich noch an das folgende Bild aus der Folge 1?
Ein verzweigtes Programm
Mit diesem Bild wurde Ihnen klar gemacht, dass ein Programmfluss durchaus verzweigt sein kann. Mit Hilfe von if-else-Anweisungen kann man eine solche Verzweigung in Java (und anderen Programmiersprachen) verwirklichen.
Neben Verzweigungen spielen aber auch Schleifen eine große Rolle bei der Entwicklung von Programmen. Wenn in einem Programm eine Folge von Anweisungen (ein sogenannter Block) immer wieder neu ausgeführt werden soll, dann setzt man eine Programmschleife dazu ein.
Zu einer solchen Programmschleife gehört eine Schleifenbedingung. Das ist eine logische Bedingung, wie Sie auch bei if-else-Anweisungen eingesetzt wird. Wenn die Schleifenbedingung erfüllt ist - also den boolean-Wert true hat - dann werden die Anweisungen in der Schleife ausgeführt. Am Ende der Schleife wird wieder zum Anfang der Schleife gesprungen. In alten Programmiersprachen wie BASIC oder FORTRAN hat man dazu den GOTO-Befehl verwendet. Jede Programmzeile hatte dort eine Zeilennummer. Heute sind wir da etwas fortschrittlicher.
Schauen wir uns nun das Testprogramm, vor allem die while-Schleife darin, etwas näher an.
while (!tankLeer())
Das ist der Kopf der while-Schleife. Er besteht aus dem Schlüsselwort while (klein geschrieben!) und einer logischen Bedingung. Diese ist - genau wie bei if-else-Anweisungen - eingeklammert.
In dieser logischen Bedingung wird die sondierende boolean-Methode tankLeer() aufgerufen (die Sie noch implementieren müssen). Wenn der Tank leer ist, liefert diese Methode den Wert true zurück. Wenn die Schleifenbedingung aber den Wert true hat, heißt das, dass die Anweisungen der Schleife ausgeführt werden sollen. Wir wollen ja aber genau das Gegenteil. Das Auto soll NICHT fahren, wenn tankLeer() den Wert true zurückliefert. Das Auto soll fahren, wenn tankLeer() den Wert false zurückliefert. Damit das Auto aber fahren kann, muss die Schleifenbedingungtrue sein. Wie kann man aus dem boolean-Wert false nun den Wert true erzeugen. Ganz einfach, mit dem NOT-Operator ! .
Der Ausdruck !tankLeer() liefert den Wert true, wenn der Tank NICHT leer ist.
Damit hätten wir den Schleifenkopf mit der Schleifenbedingung ausführlich besprochen. Wenn Sie jetzt noch Fragen haben sollten, wenden Sie sich an Ihren Lehrer oder Ihre Lehrerin.
Als Nächstes sehen wir eine geöffnete geschweifte Klammer {. Das ist das Zeichen dafür, dass jetzt Anweisungen kommen, die in der Schleife ausgeführt werden sollen. Das Ende dieser Anweisungsliste ist erreicht, wenn die geschlossene geschweifte Klammer } kommt.
Die Anweisungen selbst kennen wir bereits. Das Auto soll 10 km fahren, dann werden die beiden Werte Kilometerstand und Benzinstand in der Konsole angezeigt.
Die geschlossene geschweifte Klammer } ist jetzt das Signal für die Anwendung, zum Schleifenkopf zurück zu springen. Hier wird die Schleifenbedingung erneut überprüft. Wenn der Tank jetzt leer ist, also die Bedingung !tankLeer()den Wert false zurückliefert, wird die Schleife beendet. Das Programm springt jetzt zu der ersten Anweisung vor, die unter der geschlossenen geschweiften Klammer }steht, und führt diese aus.
In unserem Beispiel-Quelltext kommt nun aber keine weitere Anweisung mehr, das Programm wird hier also beendet.
In diesem Lexikon-Artikel wird das Thema "while-Schleifen" etwas näher beleuchtet.
In dem Lernbaustein finden Sie weitere Informationen zu while-Schleifen.
Seitenanfang -
Weiter mit Folge 4.2: while-Schleifen ...