»Programmieren«, WS 2006/2007 Nino Simunic M.A. Nino Simunic ([email protected]) Übungsblatt 4 Aufgabe 1 OOP In dieser Aufgabe sollen Sie Autos als Klasse Car modellieren. Die Eigenschaften auf attributiver Ebene sind: - Die Beschreibung des PKW Die Tankkapazität, bspw. 60 (l) Der Tankinhalt, bspw. 24.5 (l) Der Spritverbrauch, bspw. 5.7 (l) (auf 100km) Die maximale Reichweite des PKW, bspw. 600 (km) Die bislang gefahrene Strecke, bspw. 400 (km) [ carDesc ] [ fuelCap ] [ fuel ] [ fuelConsum ] [ maxRange ] [ drivenKm ] Ein beliebiges Car-Objekt soll die Möglichkeit haben, eine Strecke zu hinterlegen. Dabei soll angegeben werden können (Parameter), wie weit das Auto fahren soll. Diese Streckenangabe soll dann verwendet werden, den Spritverbrauch für die zurückzulegende Strecke zu berechnen und den verbrauchten Sprit vom Tankinhalt abzuziehen. Außerdem ist eine Methode in der Klasse zu implementieren, welche alle Daten zur aktuellen PKW-Instanz als (konkatenierten) String zurückgibt, um ebenjene bspw. auf dem Bildschirm ausgeben zu können. Es sind neben den Instanzvariablen folglich die nachstehenden Methoden zu implementieren: - Fahren Informationen ausgeben [ void drive( int distance ){ } ] [ public1 String toString( ){ } ] Bisher haben Sie nur Methoden kennengelernt, die keinen Rückgabewert produzieren. Diese müssen mit dem Schlüsselwort void im Methodenkopf definiert werden. Alle anderen Methoden geben den Typ des Rückgabewerts an, also wie bereits vorgeschlagen: String toString(){}. Die Angabe eines Rückgabetyps verpflichtet dazu, einen Wert entsprechenden Typs auch zurückzugeben, und zwar via Schlüsselwort return (gefolgt vom Rückgabewert) innerhalb der Methode. Dabei ist auch zu beachten, dass die return-Anweisung als zuletzt durchführbare Anweisung implementiert wird. Zur Verdeutlichung schauen Sie sich einmal die folgenden Varianten an: 1 2 3 4 5 6 1 Code-Ausschnitt 1 (Methode mit String-Rückgabewert) //... public String toString(){ String theString = "Alle "+"relevanten "; theString = theString + "Informationen sind hier\n"; //Konkatenation return theString; }//... public ist in diesem Fall Pflicht! Programmieren Nino Simunic M.A. Seite 1 Code-Ausschnitt 2 (Methode mit String-Rückgabewert) //... public String toString(){ return "Alle relevanten Informationen sind hier\n"; }//... 1 2 3 4 Wenn eine solche Methode mit Rückgabewert aufgerufen wird, kann (muss aber nicht) an aufrufender Stelle der Rückgabewert »aufgefangen«/verwendet werden, bspw. als Zuweisung zu einer Variablen kompatiblen Typs! ReturnTest.java public class ReturnTest { 1 2 3 4 5 6 7 8 9 10 11 12 14 public String toString( ){ return "Informationen..."; } public static void main ( String args[] ){ ReturnTest rt = new ReturnTest(); System.out.println( rt.toString() );// Bspw. so, String myString = rt.toString(); // oder als Zuweisung. System.out.println( myString ); // Wie in Zeile 9, nur mit Var. } } http://cl.informatik.uni-duisburg.de/simunic/prog0607/Aufgaben/Code/ReturnTest.java Hier noch ein paar Formeln, die Sie benötigen werden, als Pseudocode: Maximale Reichweite = Tankinhalt * 100 / Spritverbrauch Verbrauchter Sprit = Spritverbrauch * Strecke / 100 Achten Sie bei der Implementierung auf die folgenden Besonderheiten: - Wenn der verbrauchte Sprit den Tankinhalt überschreitet, wird in diesem Fall der Tankinhalt (fuel) auf 0 gesetzt, sowie die gefahrene Strecke (drivenKm) des Autos auf die max. Reichweite gesetzt. Programmieren Nino Simunic M.A. Seite 2 Als Klassengerüst für die Car-Klasse dient Ihnen die folgende Implementierung: Car.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Car { /* Instanzvariablen (attribute Eigenschaften) */ /* Konstruktor */ public String toString( ){ // Anweisungen + return-Statement zum Schluss } void drive( int distance ){ // Anweisungen } } Nehmen Sie bitte die folgende Klasse CarTest, um Car-Objekte von Ihrer Car-Klasse zu erzeugen und das Programm zu testen. CarTest.java 1 2 3 4 5 6 7 8 9 10 11 12 13 public class CarTest { public static void main ( String[] args ) { Car golfv = new Car( "Golf V TDI", 60, 6.2, 60.0); System.out.println( "Spritztour ins Allgäu bitte: 600 km"); golfv.drive( 600 ); System.out.println( golfv.toString() ); System.out.println( "\nSo, und nun zurück. "+ "Leider kein Geld mehr für's Tanken ..."); golfv.drive( 600 ); System.out.println( golfv.toString() ); } } http://cl.informatik.uni-duisburg.de/simunic/prog0607/Aufgaben/Code/CarTest.java Zur Not können Sie die main()-Methode der Testklasse oberhalb auch in Car einsetzen. Sollten Sie auf Probleme bei Berechnungen/Zuweisungen stoßen, deren Ausdrücke sowohl double als auch int-Werte enthalten, sollten Sie sich das folgende Programm IntCastTest.java einmal ansehen, bzw. auch mit uns in der Gruppe diskutieren: http://cl.informatik.uni-duisburg.de/simunic/prog0607/Aufgaben/Code/IntCastTest.java Programmieren Nino Simunic M.A. Seite 3 Wenn Sie alles richtig gemacht haben, sieht die Ausgabe im Idealfall etwas so aus: Spritztour ins Allgäu bitte: 600 km Car: Golf V TDI Fuel capacity: 60 l Fuel consumption: 6.2 l Current fuel: 22.799999999999997 l Max. range: 967 km Recently driven km: 600 km So, und nun zurück. Leider kein Geld mehr für's Tanken ... Car: Golf V TDI Fuel capacity: 60 l Fuel consumption: 6.2 l Current fuel: 0.0 l Max. range: 967 km Recently driven km: 967 km Aufgabe 2 CAR-ERWEITERUNGEN, TEIL 1 - Erweitern Sie Ihre Car-Klasse um einen weiteren Konstruktor, der ohne die Angabe von fuel auskommt. In diesem Fall wird die vorhandene Menge Sprit (fuel) einfach auf den maximalen Wert, d.h. die Tankkapazität, gesetzt (fuelCap). - Fügen Sie der Car-Klasse eine Methode public void setFuel( int fuelAmount ) { } hinzu, welche das Betanken ermöglicht. Für die Funktionalität dieser Methode ist zu beachten: o Wenn die angegebene Menge (fuelAmount) größer 0 ist, und die Summe aus der aktuell vorhandenen Spritmenge (fuel) und der zu tankenden Menge (fuelAmount) die Tankkapazität (fuelCap) nicht überschreitet, wird fuelAmount zu fuel addiert. o Ansonsten (d.h., wenn bspw. negative Werte oder fuel-überschreitende Werte als Argument übergeben werden) wird fuel auf das Maximum gesetzt (fuelCap) o In beiden Fällen wird der Tachostand (drivenKm) auf 0 gesetzt, und die Reichweite (maxRange) auf Basis der neuen Werte berechnet. - Eventuell ist es sinnvoll, die Berechnung der maximalen Reichweite in eine separate Methode zu schreiben, um Redundanzen im Code zu vermeiden. Nur bei der Ausgabe der Car-Informationen sollen double-Werte gerundet und nur mit zwei Nachkommastellen angezeigt werden. Benutzen Sie dazu die (statische) Methode round der Klasse Math. Auch in diesem Fall kann ein Blick in die Java-API nicht schaden. Hier ein kleines Anwendungsbeispiel: double myD = 2.9876543; double myRoundedD = Math.round( myD * 100. ) / 100.; //myRoundedD hat den Wert 2.99 - Welchen Vorteil bietet nun eigentlich die Methode setFuel( )? Man könnte ja theoretisch die Attribute händisch modifizieren, wenn man »tankt«, d.h. carObject.fuel = 10; carObject.maxRange = 500;? Programmieren Nino Simunic M.A. Seite 4 Aufgabe 3 CAR-ERWEITERUNGEN, TEIL 2 Sie erhalten für diese Aufgabe eine bereits kompilierte Klasse Route.class inklusive Dokumentation: http://cl.informatik.uni-duisburg.de/simunic/prog0607/Aufgaben/Code/Route.zip Im Moment arbeitet Ihre drive-Methode so, dass ein int-Wert übergeben werden kann, der via Argument/lokale Variable (distance) zu weiteren Berechnungen innerhalb der Methode herangezogen wird. Ihre Aufgabe besteht nun darin, Ihre Car-Klasse so anzupassen, dass die drive-Methode nicht mehr direkt mit einem primitiven Datentyp arbeitet/rechnet, sondern über ein Objekt auf den Entfernungswert zugreift. D.h., dass die Parameterliste der drive( )-Methode nicht mehr aus einem int-Parameter bestehen soll (distance) , sondern mit einen Route-Parameter definiert wird. Als Instanzvariable der Route-Klasse existiert die Variable routeDistance vom Typ int. Mit entsprechendem Aufruf via Punktnotation können Sie auf diesen Wert zugreifen. Prinzipiell müssen Sie dann lediglich alle Vorkommen von distance durch route.routeDistance ersetzen, vorausgesetzt natürlich, Sie haben sich für diese vorgeschlagenen Bezeichner entschieden. Zur Verdeutlichung der durchzuführenden Modifikationen sehen sich Sie bitte die Vorher-Nachher Darstellung unterhalb an. Die Anweisungen sind natürlich nur Beispiele, die Sie im Idealfall de facto nicht verwenden sollen: // ... Vorher: public void drive( int distance ) { System.out.println( distance + 1 ); }// ... ------------------------------------------// ... Nachher: public void drive( Route route ) { System.out.println( route.distance + 1 ); }// ... Zunächst sollten Sie sich jedoch mit der Route-Klasse ein wenig vertraut machen. Die Dokumentation sagt bereits einiges über die Eigenschaften der Klasse aus, u.a. welche Argumente notwendig sind, um ein Route-Objekt zu erzeugen. Was allerdings nicht in der Dokumentation steht, sind die folgenden, wohlmöglich für Sie neuen Informationen. Um die fertige Route-Klasse nutzen zu können, gibt es verschiedene Möglichkeiten. (Im Allgemeinen müssen Sie beim Kompilieren der Klasse(-n), welche die Route-Klasse verwenden, den Pfad zu der kompilierten Route-Klasse mit angeben. Diese Information ist der sogenannte classpath.) Wir einigen uns jedoch zunächst auf die folgende, einfache Variante. Programmieren Nino Simunic M.A. Seite 5 Ein Beispiel: Sie haben eine Klasse RouteTest, welche Route verwendet, geschrieben und entsprechend gespeichert: RouteTest.java 1 2 3 4 5 6 7 8 public class RouteTest { public static void main(String[] args) { Route myRoute = new Route( "Dortmund", "Duisburg", 55, 120); System.out.println( myRoute.toString() ); } } http://cl.informatik.uni-duisburg.de/simunic/prog0607/Aufgaben/Code/RouteTest.java Angenommen, sie haben die RouteTest.java Datei im Ordner D:\javaTMP gespeichert. Legen Sie nun auch die Route.class Datei im selben Verzeichnis (D:\javaTMP) ab und kompilieren Sie dann ihre .java-Datei (nicht die .class-Datei) mit javac wie gehabt. Wenn Sie mehrere .java Dateien auf einmal kompilieren wollen, können Sie dies übrigens auch mit dem Asterisk/Glob-Sternchen * tun: javac *.java Mit diesem (Konsolen-)Befehl werden alle Dateien, die auf .java enden und im selben Verzeichnis sind, kompiliert. Die hier aufgeführten Schritte können Sie sich anhand des Bilds unterhalb verdeutlichen: Heiter weiter, und gutes Gelingen! Programmieren Nino Simunic M.A. Seite 6