»Programmieren«, WS 2006/2007 Nino Simunic M.A. Nino Simunic ([email protected]) Übungsblatt 7 Die benötigten Quelltexte finden Sie hier: http://imperia.uni-due.de/imperia/md/content/computerlinguistik/uebungsblatt_7_code.zip Aufgabe 1 VERERBUNG IN JAVA: (OBERKLASSEN-)KONSTRUKTOREN C.java class A { A( ){ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 System.out.println(">>A<<"); } } class B extends A{ B() { System.out.println(">>B<<"); } } public class C extends B { C() { System.out.println(">>C<<"); } public static void main (String [] args) { new C(); } } Bevor Sie das Programm ausführen: Was ist Ihrer Meinung nach die Ausgabe? Kompilieren und führen Sie das Programm aus. o Was ist die Ausgabe de facto? Entspricht die Ausgabe Ihren Erwartungen? Formulieren Sie ein Prinzip im Kontext Vererbung, welche das beobachtbare Verhalten erklärt. Das Prinzip soll im Kern die Reihenfolge der Aufrufe von Konstruktoren bei Vererbung beschreiben. Warum werden Konstruktoren der Oberklasse überhaupt aufgerufen, obwohl kein super() in der vorliegenden Mehrfachvererbung explizit verwendet wurde? Programmieren Nino Simunic M.A. Seite 1 Aufgabe 2 INSTANCEOF In dieser Aufgabe erlernen Sie den Umgang mit einem neuen, binären Operator: instanceof. Versuchen Sie zu verstehen, was dieser Operator leistet, um ihn später auch anwenden zu können. http://www.dpunkt.de/java/Die_Sprache_Java/Objektorientierte_Programmierung_mit_Java/48.html: Mit dem instanceof-Operator kann zur Laufzeit geprüft werden, ob ein von einem Verweis referenziertes Objekt zuweisungskompatibel zu einer Klasse ist, die im zweiten Operanden von instanceof angegeben wird. Der zweite Operand darf kein Verweis sein. instanceof hat die Syntax <Verweis oder Verweistyp> instanceof <Verweistyp> instanceof liefert true, wenn • der linke Operand eine Variable mit einem Verweistyp ist und zur Laufzeit auf ein Exemplar verweist, das zu der Klasse (oder einer Unterklasse) gehört, die der zweite Operand vorgibt. instanceof liefert false, wenn • • der linke Operand den Wert null hat, da dieser Wert anzeigt, dass auf kein Objekt verwiesen wird; der linke Operand eine Variable mit einem Verweistyp ist und zur Laufzeit auf ein Exemplar verweist, das nicht zu der Klasse (oder einer Unterklasse) gehört, die der zweite Operand vorgibt. Mit instanceof kann zum Beispiel zunächst festgestellt werden, ob zwei Objekte zuweisungskompatibel sind, bevor die eigentliche Zuweisung erfolgt. Schauen Sie sich zur Verdeutlichung den folgenden Code an: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 instanceTest.java class Ship { /* Code */ } class Yacht extends Ship { /* Code */ } class Carrier extends Ship { /* Code */ } public class instanceTest { public static void main (String[] args){ /* Links deklarierter Typ, rechts tatsächlicher Typ */ Ship speedy = new Yacht(); Ship nimitz = new Carrier(); if ( speedy instanceof Yacht ){System.out.println("Is a yaught!");} if ( nimitz instanceof Carrier ){ System.out.println("Is a carrier!");} if ( nimitz instanceof Ship ){ System.out.println("Is also a ship!");} } } Programmieren Nino Simunic M.A. Seite 2 Dank Polymorphie (und dank Informatik ;) sind die Zeilen 8-10 erst möglich: Eine Objektreferenz kann an eine Variable anderen (kompatiblen!) Typs zugewiesen werden, wenn der Typ dieser Variablen in der Vererbungshierarchie höher steht als der Typ des zuzuweisenden Objekts: Yacht ist eine abgeleitete Klasse von Ship, und somit ist die Zuweisung an einer Variable vom (höheren) Typ Ship in Ordnung. Für Zeile 10 gilt Analoges. Da also ein Objekt Instanz seiner Klasse und aller in der Hierarchie höher angesiedelten Klassen ist, wird die Bedingung in Zeile 15 auch als true ausgewertet. Ändern Sie die main-Methode so wie unterhalb angegeben, und führen Sie das Programm dann aus. instanceTest.java (nur main-Methode) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static void main (String[] args){ Ship seaStar = new Yacht(); if ( seaStar instanceof Ship ) { System.out.println("Is a boring ship!"); } else if ( seaStar instanceof Carrier ) { System.out.println("Is a carrier!"); } else if ( seaStar instanceof Yacht ) { System.out.println("Is a nice yacht!"); } } Die Ausgabe ist zwar nicht »falsch«, jedoch nicht gewollt: Es soll der tatsächliche Typ ausgegeben werden. Ändern Sie die Kontrollstruktur so, dass der tatsächliche Typ ausgegeben wird. Es sollen alle Überprüfungen noch immer vorgenommen werden. Ändern Sie den Typ von seaStar zu Yacht. Warum (und wo) lässt sich das Programm jetzt nicht mehr kompilieren? Aufgabe 3 PERSONEN-REPOSITORY, INSTANCEOF Besorgen Sie sich die Klassen Person.java, Student.java, Lecturer.java aus der letzten Vorlesung, bzw. via Link am Anfang des Übungsblatts. Ihre Aufgabe besteht darin, die unterhalb aufgeführte Repository-Klasse um die Methode isA zu erweitern. Die Methode isA soll als Rückgabewert ein String besitzen, welcher den Typ des übergebenen Objekts beschreibt: "Person“, "Student“, bzw. "Lecturer“. Verwenden Sie als Gerüst und zum Testen die nachstehende Klasse, die bereits Aufrufe der (noch nicht existierenden) isA-Methode in der main-Methode enthält. Programmieren Nino Simunic M.A. Seite 3 1 2 3 4 5 6 7 8 9 10 11 12 13 Repository.java public class Repository { // ... isA( ... ) { ... } public static void main(String[] args){ Person[] repository = new Person[3]; repository[0] = new Person("Pladimir Vutin", "1.4.1955", 'f'); repository[1] = new Student("Ochse Uwenknecht","7.8.1982",'m',100001000); repository[2] = new Lecturer("Dr. Mabuse", "9.9.1915", 'm', 195644432, 15000); System.out.println( isA(repository[0])+": "+ repository[0].toString() ); System.out.println( isA(repository[1])+": "+ repository[1].toString() ); System.out.println( isA(repository[2])+": "+ repository[2].toString() ); } } Wenn Sie die isA-Methode korrekt implementiert haben, ist die Ausgabe: Person: Pladimir Vutin, 1.4.1955, f Student: Ochse Uwenknecht, 7.8.1982, m, 100001000 Lecturer: Dr. Mabuse, 9.9.1915, m, 195644432, 15000.0 Enthält Ihre Methode eine if-else if(-else) Kontrollstruktur, müssen Sie auch darauf achten, dass jeder erreichbare und ausführbare Teil (auch der else-Rumpf, der nicht zwingend explizit via else manifestiert werden muss) auch eine returnAnweisung enthält! Aufgabe 4 PKW-VERERBUNG Modellieren Sie die folgenden Konzepte, indem Sie sie als Klassen Auto, Pickup und AutoTest verwirklichen. Eigenschaften von Objekten dieser Klassen sollen ausschließlich beim Erzeugen gesetzt und ggf. durch Methoden verändert werden können. Auto: Ein Auto soll ein Kennzeichen, einen Kilometerstand und eine Anzahl Sitzplätze haben. Wenn nicht anders angegeben, ist das Kennzeichen eines Auto–Objekts standardmäßig »DO-OM 3«, es sollen aber auch Autos mit anderen Kennzeichen erzeugt werden können. Ein neu erzeugtes Auto hat grundsätzlich noch keine Kilometer gefahren. Wenn nicht anders angegeben, so hat ein Auto 5 Sitzplätze. Es sollen jedoch auch zweisitzige Autos erzeugt werden können. Zu guter Letzt hat ein Auto eine Antenne, die aus- oder eingefahren werden/sein kann. Die Klasse soll mindestens die folgenden Methoden besitzen: Programmieren Nino Simunic M.A. Seite 4 public String getKennzeichen() : liefert das Kennzeichen zurück public int getKilometerstand() : liefert den aktuellen Kilometerstand zurück public void fahre(int x) : schreibt eine Meldung an die Standardausgabe, dass das Auto x Kilometer fährt, und setzt dann den Kilometerstand entsprechend weiter public void antenneEinfahren() : schreibt eine Meldung an die Standardausgabe, dass die Antenne eingefahren wird, und setzt den Status der Antenne public void antenneAusfahren() : schreibt eine Meldung an die Standardausgabe, dass die Antenne ausgefahren wird, und setzt den Status der Antenne public boolean istAntenneDraussen() : liefert genau dann true, wenn die Antenne ausgefahren ist protected void vorDemWaschen() : bereitet das Auto auf den Aufenthalt in der Waschstraße vor – konkret bedeutet das bei einem Auto, dass die Antenne eingefahren wird public void waschen() : bereitet das Auto für eine Wagenwäsche vor und schreibt dann eine Meldung an die Standardausgabe, dass der Wagen gewaschen wird public int getSitzplaetze() : liefert die Anzahl Sitzplätze zurück public boolean equals(Object o) : ergibt genau dann true, wenn das Objekt o ebenfalls ein Auto ist, und wenn die beiden Kennzeichen gleich sind public String toString() : gibt eine passende String–Repräsentation des Autos zurück Pickup: Ein Pickup ist für unsere Zwecke eine spezielle Art von Auto. Es hat nur 2 Sitzplätze, dafür jedoch zusätzlich eine offene Ladefläche mit einem beim Erzeugen bestimmbaren Fassungsvermögen f. Die Ladefläche ist beim Erzeugen des Pickups zunächst leer und kann maximal mit f Dingen beladen werden. Die Klasse muss mindestens folgende Methoden besitzen: public boolean beladen(int x) : falls auf der Ladefläche noch genügend Platz ist, wird der Inhalt der Ladefläche um x Dinge erhöht, eine passende Meldung an die Standardausgabe geschrieben, und true zurückgegeben, andernfalls false public void entladen(int x) : falls auf der Ladefläche mindestens x Dinge vorhanden sind, wird der Inhalt der Ladefläche um x Dinge erniedrigt, eine passende Meldung geschrieben, und true zurückgegeben, andernfalls false protected void vorDemWaschen() : bei einem Pickup soll vor dem Waschen nicht die Antenne eingefahren werden, sondern stattdessen die Ladefläche geleert werden public int getLadung() : liefert die Anzahl Dinge, die derzeit auf der Ladefläche liegen, zurück, ohne den Ladezustand zu verändern public String toString() : gibt eine passende String–Repräsentation des Pickups zurück AutoTest: Diese Klasse ist ausschließlich zum Testen der Klassen Auto und Pickup da. Definieren Sie in AutoTest eine passende main–Methode, in der mehrere verschiedene Autos und Pickups erzeugt werden. Dort ist unter anderem Folgendes zu implementieren: Lassen Sie sich die Kennzeichen und sonstigen Zustände der erzeugten Objekte ausgeben. Lassen Sie die Autos und Pickups fahren, waschen. Testen Sie sie untereinander auf Gleichheit. Testen Sie die Beladelogik der Pickups. Hinweis: Der Modifikator protected bewirkt bei Methoden und Variablen, dass diese nur innerhalb der betreffenden Klasse und aller Klassen, die von ihr erben, sichtbar sind. Der Modifikator private dagegen bewirkt eine Sichtbarkeit nur innerhalb der betreffenden Klasse. Der Modifikator public bewirkt eine allgemeine Sichtbarkeit. Programmieren Nino Simunic M.A. Seite 5