Vergleich der DoME Realisierungen: Methode ausgeben Version 1 (ohne Vererbung): Anzeigen aller Informationen CD: A Swingin Affair (64 Min)* Frank Sinatra Titelanzahl: 16 Mein Lieblingsalbum von Sinatra DVD: Matrix (136 Min) Andy & Larry Wachowski Toller Film über Virtual Reality public class Medium { public void ausgeben() { System.out.print("Titel: " + titel + " (" + spielzeit + " Min)"); if (habich) { System.out.println("*"); else { System.out.println(); System.out.println(" " + kommentar); Version 2 (mit Vererbung): Informationen fehlen A Swingin Affair (64 Min)* Mein Lieblingsalbum von Sinatra Matrix (136 Min) Toller Film über Virtual Reality 256
Vererbung ist eine Einbahnstrasse: CD bzw. DVD erbt die Datenfelder von Medium, aber Medium weiß nichts über die Datenfelder von CD bzw. DVD In Methode ausgeben in Medium sind die spezifischen Datenfelder von CD und DVD (z.b. kuenstler usw.) nicht verfügbar und können deshalb nicht ausgedruckt werden 257
Variante: Methode ausgeben in Subklassen verschieben Wir bekommen Fehlermeldungen in Klassen CD und DVD, weil wir dort nicht auf die Datenfelder der Superklasse zugreifen können Privatsphäre zwischen Super- und Subklasse: Eine Subklasse kann nicht direkt auf die privaten Anteile ihrer Superklasse zugreifen. Der Zugriff erfolgt indirekt durch sondierende und verändernde Methoden der Superklasse. Wir bekommen eine Fehlermeldung in Klasse Datenbank, weil dort die Methode ausgeben nicht gefunden werden kann 258
public class Datenbank { public void auflisten() { for(iterator iter = medien.iterator(); iter.hasnext(); ) { Medium medium = (Medium)iter.next(); medium.ausgeben(); 2. Fehlermeldung in Klasse Datenbank ist logisch, aber dennoch ärgerlich. Jedes Medium ist entweder ein CD oder DVD und beide Klassen haben eine Methode ausgeben. 259
Statischer Typ: Jede Variable v hat einen statischen Typ, mit dem v im Quelltext der Klasse definiert wird Dynamischer Typ: Jede Variable v hat auch einen dynamischen Typ von dem Objekt, das zur Zeit in v gehalten wird Beispiel: Medium medium = new DVD( ); Der statische Typ von medium ist Medium, der dynamische Typ von medium ist DVD Der dynamische Typ ist häufig erst zur Laufzeit bekannt und deshalb wird bei der Typüberprüfung ausschließlich der statische Typ berücksichtigt. Dies erklärt die 2. Fehlermeldung in Klasse Datenbank. 260
Variante: Methode ausgeben in Superklasse und Subklassen: Eine Subklasse kann die Implementierung einer Methode in der Superklasse überschreiben. Dazu deklariert die Subklasse eine Methode mit derselben Signatur wie in der Superklasse, implementiert diese jedoch mit einem anderen Rumpf. Bei einem Objekt medium, das zur Laufzeit ein DVD hält, sind zwei Methoden mit demselben Namen und Signatur vorhanden. Welche wird beim Aufruf medium.ausgeben() ausgeführt? 261
public class Medium { public void ausgeben() { // Wie bisher in Version 2 mit Vererbung public class CD extends Medium { public void ausgeben() { System.out.println(" " + kuenstler); System.out.println(" " + titelanzahl + " Titel"); Public class DVD extends Medium { public void ausgeben() { System.out.println(" Regisseur: " + regisseur); 262
Aufruf medium.ausgeben() liefert: Frank Sinatra 16 Titel Regisseur: Andy & Larry Wachowski Das sind Ausgaben der Methode ausgeben von Klasse CD und DVD! Seltsam (auf den ersten Blick): Der Compiler besteht auf eine Methode ausgeben in der Klasse Medium. Die Methoden in den Subklassen reichen nicht aus. Methode ausgeben der Klasse Medium wird überhaupt nicht ausgeführt, stattdessen die der Subklassen Wichtig: Die Typüberprüfung berücksichtigt den statischen Typ, aber zur Laufzeit werden die Methoden des dynamischen Typs ausgeführt 263
Dynamische Methodensuche: Fall 1: Ein Objekt der Klasse DVD, das in einer Variablen v1 vom statischen Typ DVD gespeichert ist Auf v1 wird zugegriffen Das in v1 gespeicherte Objekt wird gefunden (Verfolgung der Referenz) Die Klasse des Objektes wird gefunden (Verfolgung der Referenz ist Instanz von ) Die Implementierung der Methode ausgeben wird in der Klasse gefunden und ausgeführt 264
Fall 2: (Vererbung) Die Methode ausgeben ist ausschließlich in der Superklasse definiert Die ersten drei Schritte wie im Fall 1 In Klasse DVD wird keine Methode ausgeben gefunden In der Superklasse Medium wird die Methode ausgeben gefunden und ausgeführt 265
Verallgemeinerung: Wenn auch in der Superklasse die Methode nicht gefunden wird, wird die nächste Superklasse durchsucht. Dies setzt sich durch die Vererbungshierarchie nach oben bis zur Klasse Object hin fort, bis eine Methode gefunden wird. Bemerkung: Zur Laufzeit wird garantiert eine passende Methode gefunden, sonst hätte die Klasse vom Compiler nicht übersetzt werden können. 266
Fall 3: (Vererbung) Die dynamische Methodensuche mit einer polymorphen Variablen v1 und einer überschriebenen Methode Die Situation ist Fall 2 recht ähnlich. Zwei Änderungen: Der deklarierte Typ von v1 ist Medium, nicht DVD Die Methode ausgeben ist definiert in Klasse Medium und überschrieben in Klasse DVD Dieselben vier Schritte wie im Fall 1 werden ausgeführt 267
Welche Methode zuerst gefunden und ausgeführt wird, hängt vom dynamischen Typ ab, nicht vom statischen Typ. Bsp. Der deklarierte Typ Medium der Variablen v1 spielt keine Rolle. Die Instanz, mit der wir hier umgehen ist von der Klasse DVD Das ist das Einzige, was zählt. Überschreibende Methoden in Subklassen haben Vorrang vor Methoden aus Superklassen. Da die Methodensuche in der dynamischen Klasse der Instanz beginnt (am unteren Ende der Vererbungshierarchie), wird die letzte Redefinition einer Methode zuerst gefunden und ausgeführt. Wenn eine Methode überschrieben ist, dann wird nur die letzte Version ausgeführt. Versionen der gleichen Methode in den Superklassen werden nicht automatisch ebenfalls ausgeführt. Ausgaben auf Folie 263 268
public class Medium { public void ausgeben() { // Wie bisher in Version 2 mit Vererbung public class CD extends Medium { public void ausgeben() { super.ausgeben(); System.out.println(" " + kuenstler); System.out.println(" " + titelanzahl + " Titel"); Public class DVD extends Medium { public void ausgeben() { super.ausgeben(); System.out.println(" Regisseur: " + regisseur); 269
super-konstrukt: vgl. Konstruktor von Subklassen Allgemeine Form: super.methodenname(parameterliste) Die Parameterliste kann leer sein Der super-aufruf kann an jeder beliebigen Stelle in einer Methode erfolgen. Er muss nicht die erste Anweisung sein. Es muss kein super-aufruf erfolgen und es wird auch nicht automatisch ein Aufruf generiert. Auf diese Weise ergibt sich das Standardverfahren, dass eine überschreibende Methode die entsprechende Version aus der Superklasse komplett verdeckt. 270
Methoden-Polymorphie: Methodenaufrufe in Java sind polymorph. Derselbe Methodenaufruf kann zu unterschiedlichen Zeitpunkten verschiedene Methoden aufrufen, abhängig vom dynamischen Typ der Variablen, mit der der Aufruf durchgeführt wird. Beispiel: Der Aufruf medium.ausgeben(); kann zu einem Zeitpunkt die ausgeben-methode von CD einer CD aufrufen und zu einem anderen die ausgeben-methode eines DVDs, je nach referenziertem Objekt, also je nach dem dynamischen Typ der Variablen medium. 271
5.10.8 Methoden aus Object: tostring Die universelle Superklasse Object implementiert einige Methoden, die somit alle Objekte anbieten. Die spannendste dieser Methoden: tostring(): eine String-Repräsentation eines Objektes liefern Die Standardimplementierung von tostring in Klasse Object kann nicht sehr viele nützliche Details anzeigen Beispiel: Aufruf von tostring an einem DVD-Objekt liefert DVD@6acdd1 Das Ergebnis zeigt den Namen der Klasse des Objektes und eine interne Zahl (Speicheradresse, an der dieses Objekt gespeichert ist) 272
5.10.8 Methoden aus Object: tostring 273
5.10.8 Methoden aus Object: tostring Jedes Objekt in Java bietet eine Methode tostring an, die eine String-Repräsentation des Objektes liefert. Um diese Methode nützlich zu machen, kann sie in Subklassen überschrieben werden. public class Medium { public String tostring() { String zeile1 = titel + ( + spielzeit + Min) ); if (habich) { return zeile1 + *\n + + kommentar + \n ); else { return zeile1 + \n + + kommentar + \n ); public void ausgeben() { System.outprintln(toString()); 274
5.10.8 Methoden aus Object: tostring public class CD extends Medium { public String tostring() { return super.tostring() + + kuenstler + \n + titelanzahl + Titel + \n ; public void ausgehen() { System.out.println(toString()); 275
5.10.8 Methoden aus Object: tostring Großer Vorteil von tostring(): Wir schreiben nicht vor, was mit dem Text tatsächlich passiert. Es steht jedem Klienten (z.b. Klasse Datenbank) frei, wie er mit dem Text umgeht: auf der Konsole ausgeben System.out.println(medium.toString()); im Textbereich einer grafischen Benützerschnittstelle ausgeben in eine Datei speichern über ein Datennetz verschicken medium.tostring() ruft je nach dem dynamischen Typ von medium die Methode tostring von der Klasse CD oder DVD auf 276
5.10.8 Methoden aus Object: tostring Besonderheit der Methode System.out.print und System.out.println: Wenn der Parameter nicht vom Typ String ist, dann wird in der Methode automatisch an dem übergebenden Objekt die Methode tostring aufgerufen. Es reicht also: System.out.println(medium); Entsprechende Version der Klasse Datenbank: public class Datenbank { public void auflisten() { for (Iterator iter = medien.iterator(); iter.hasnext(); ) { System.out.println(iter.next()); 277
5.10.8 Methoden aus Object: tostring Der Aufuf von iter.next() liefert einen Wert mit dem statischen Typ Object. Der dynamische Typ ist entweder CD oder DVD. Da dieses Objekt mit System.out ausgegeben wird und es kein String ist, wird automatisch seine tostring-methode aufgerufen Der Aufruf dieser Methode ist nur deshalb zulässig, weil die Klasse Object (der statische Typ!) eine tostring-methode deklariert. Wichtig: Die Typüberprüfung erfolgt mit dem statischen Typ. Die Ausgabe zeigt alle Details an, weil alle möglichen dynamischen Typen (CD und DVD) die tostring-methode überschreiben und die dynamische Methodensuche gewährleistet, dass die jeweils passende Methode aufgerufen wird. Mithilfe von tostring können wir die ausgeben-methoden komplett aus den Klassen verbannen 278
5.10.9 Finale Klassen und Methoden Das Schlüsselwort final verhindert, dass eine Methode überschrieben wird public final void X () Das Schlüsselwort final verhindert, dass Klassen von einer weiteren Klasse abgeleitet werden können public final class CD extends Medium Von CD können keine weiteren Subklassen durch Vererbung abgeleitet werden. Alle Methoden einer finalen Klasse sind implizit auch final. 279
5.10.10 Zugriff über protected Zugriffsrechte für Attribute und Methoden: private: Methoden und Attribute sind nur in der Klasse zugreifbar, in der sie definiert sind public: Methoden und Attribute sind von allen Klassen aus zugreifbar protected: Methoden und Attribute sind in der Klasse selbst und von allen (direkten und indirekten) Subklassen zugreifbar protected sollte den Konstruktoren und Methoden vorbehalten bleiben Datenfelder werden üblicherweise nicht als protected deklariert, da dies die Kapselung schwächen würde. Soweit möglich, sollten veränderbare Datenfelder in Superklassen privat bleiben und über sondierende/verändernde Methoden angesprochen werden. 280
5.10.10 Zugriff über protected Die ovalen Bereiche kennzeichnen jeweils die Gruppen der Klassen, die auf Teile der Klasse EineKlasse zugreifen können 281