Lösungsvorschläge

Transcription

Lösungsvorschläge
TECHNISCHE
UNIVERSITÄT
MÜNCHEN
FAKULTÄT FÜR INFORMATIK
Praktikum Grundlagen der Programmierung
Lösungsvorschläge zu Blatt 7
Robert Eigner, Florian Forster
Praktikum Grundlagen der Programmierung
Aufgabe 34 Mehrfachvererbung (Lösungsvorschlag)
a) Vererbungsmodell:
b) Die abstrakte Oberklasse für alle Superhelden:
public abstract class Superheld {
abstract public void kaempfen ();
}
Die Schnittstelle für fliegende Superhelden:
public interface KannFliegen {
public void fliegen ();
}
Die Schnittstelle für denkende Superhelden:
public interface KannDenken {
public void denken ();
}
SS 2010
14.06.2010
Lösung 7/ Seite 2
Die Schnittstelle für Karate-Superhelden:
public interface KannKarate {
public void karate ();
}
Einzelne Vertreter der Superhelden-Gattungen:
public class Conan extends Superheld {
public void kaempfen () {
System . out . println (" Conan kämpft " );
}
}
public class Superman extends Superheld implements KannFliegen {
public void kaempfen () {
System . out . println (" Superman kämpft " );
}
public void fliegen () {
System . out . println (" Superman fliegt " );
}
}
public class Spiderman extends Superheld
implements KannFliegen , KannDenken {
public void kaempfen () {
System . out . println (" Spiderman kämpft " );
}
public void fliegen () {
System . out . println (" Spiderman fliegt " );
}
public void denken () {
System . out . println (" Spiderman denkt " );
}
}
public class ChuckNorris extends Superheld implements KannKarate {
public void kaempfen () {
System . out . println (" Chuck Norris kämpft " );
}
public void karate () {
System . out . println (" Chuck Norris kann Karate " );
}
}
Lösung 7/ Seite 3
Aufgabe 35 verkettete Listen (Lösungsvorschlag)
public class IntNode {
private int value ;
private IntNode next ;
public IntNode (int i) {
value = i;
}
public int getValue () {
return value ;
}
public void setValue (int i) {
value = i;
}
public IntNode getNext () {
return next ;
}
public void setNext ( IntNode n) {
next = n;
}
}
public class LinkedIntList {
private IntNode first ;
public LinkedIntList () {
first = null;
}
public boolean isEmpty () {
return first == null;
}
public void insert (int i) {
if ( first == null) {
first = new IntNode (i );
} else {
IntNode current = first ;
while( current . getNext () != null) {
current = current . getNext ();
}
current . setNext (new IntNode (i ));
}
}
Lösung 7/ Seite 4
public void remove (int i) {
IntNode current = first ;
IntNode predecessor = first ;
while( current != null) {
if ( current . getValue () == i) {
if ( current . getNext () != null) {
current . setValue ( current . getNext (). getValue ());
current . setNext ( current . getNext (). getNext ());
} else {
if ( current == first ) {
first = current = predecessor = null;
} else {
predecessor . setNext (null);
}
}
return;
}
predecessor = current ;
current = current . getNext ();
}
}
@Override
public String toString () {
StringBuffer sb = new StringBuffer ();
IntNode current = first ;
while ( current != null){
sb . append ( current . getValue ()). append ( ’ ’);
current = current . getNext ();
}
return sb . toString ();
}
}
Alternative Lösung, die nicht jedesmal die komplette Liste bis ans Ende durchlaufen muss, wenn
am Ende ein Element eingefügt werden soll. Dies wird erreicht, indem ein zweiter Zeiger mitgeführt wird, der auf das Ende der Liste zeigt:
public class LinkedIntList {
private IntNode head , last ;
public boolean isEmpty () {
return head == null;
}
public void insert (int i) {
if ( isEmpty ()) {
head = new IntNode (i );
last = head ;
} else {
last . setNext (new IntNode (i ));
last = last . getNext ();
Lösung 7/ Seite 5
}
}
public void remove (int i) {
if (! isEmpty ()) {
if ( head . getValue () == i) {
if ( last == head )// remove the last element (in this case
// the head) of the list => update last
// reference
last = null;
head = head . getNext ();
} else {
IntNode current = head ;
while ( current . getNext () != null
&& current . getNext (). getValue () != i)
current = current . getNext ();
if ( current == last )// not found => return
return;
if ( last == current . getNext ())// remove the last element
// of the list => update
// last reference
last = current ;
current . setNext ( current . getNext (). getNext ());
}
}
}
@Override
public String toString () {
StringBuffer sb = new StringBuffer ();
IntNode current = head ;
while ( current != null) {
sb . append ( current . getValue ()). append (" " );
current = current . getNext ();
}
return sb . toString ();
}
}
Lösung 7/ Seite 6
Aufgabe 36 Overriding & Overloading (Lösungsvorschlag)
Ja, das Programm kompiliert und erzeugt folgende Ausgabe:
Konstruktor
Konstruktor
Konstruktor
A. test ()
B. test ()
---------Konstruktor
Konstruktor
B. test ()
---------Konstruktor
Konstruktor
Konstruktor
C. test ()
A. test ()
---------Konstruktor
Konstruktor
Konstruktor
C. test ()
B. test ()
---------A. test ()
D. test (A a)
B. test ()
D. test (A a)
B. test ()
D. test (B b)
A
A
B
A
B
A
B
C(A a)
A
B
C(A a)
Overriding (Überschreiben): eine Methode einer Subklasse hat den gleichen Namen, dieselbe Paramterliste und denselben Rückgabewert wie eine Methode seiner Elternklasse: die Subklasse
überschreibt eine Methode seiner Elternklasse. Eine überschreibende Methode kann auch einen
Untertyp des Typs zurückgeben, der von der überschriebenen Methode zurückgegeben wird (kovarianter Rückgabetyp). Der Zugriffsmodifizierer der überschreibenden Methode darf dabei nicht
einschränkender sein als der der überschriebenen Methode, d. h. eine Methode die public deklariert ist kann nicht mit einer als protected deklarierten Methode überschrieben werden.
Zur Fehlervermeidung sollte die b̈erschreibende Methode in der Subklasse mit der @OverrideAnnotation (verfügbar seit Java 1.5) gekennzeichnet werden. Bei deren Verwendung wird vom
Compiler dann überprüft, ob die entsprechend gekennzeichnete Methode tatsächlich eine Methode einer Elternklasse überschreibt. Die Typüberprüfung wird schon vom Compiler durchgeführt.
Overloading (Überladen): innerhalb einer Klasse sind mehrere Methoden mit gleichem Namen
aber unterschiedlicher Parameterliste vorhanden (Anzahl und/oder Typ der Parameter sind verschieden): die Methoden sind „überladen“. Der Rückgabetyp ist dabei irrelevant, d. h. eine Klasse
kann nicht über zwei Methoden mit demselben Namen und derselben Parameterliste verfügen, die
sich nur im Rückgabetyp unterscheiden. Die überladenen Methoden müssen dabei nicht zwingend
in derselben Klasse definiert sein. So kann eine Methode einer Subklasse eine von der Elternklasse
geerbte Methode überladen. Die Typüberprüfung wird erst zur Laufzeit durchgeführt. Somit wird
auch erst zur Laufzeit festgestellt, welche Methode aufzurufen ist.