From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001 From: Sven Eisenhauer Date: Fri, 10 Nov 2023 15:11:48 +0100 Subject: add new repo --- .../hjp5/html/k100052.html | 604 +++++++++++++++++++++ 1 file changed, 604 insertions(+) create mode 100644 Master/Reference Architectures and Patterns/hjp5/html/k100052.html (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100052.html') diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100052.html b/Master/Reference Architectures and Patterns/hjp5/html/k100052.html new file mode 100644 index 0000000..f5ff07b --- /dev/null +++ b/Master/Reference Architectures and Patterns/hjp5/html/k100052.html @@ -0,0 +1,604 @@ + + + +Handbuch der Java-Programmierung, 5. Auflage + + + + + + + + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage +
 <<  +  <   +  >   + >>  + API  +Kapitel 8 - OOP II: Vererbung, Polymorphismus und statische Elemente +
+
+ + + + +

8.1 Vererbung

+
+ +
+ +

+Eines der wesentlichen Designmerkmale objektorientierter Sprachen +ist die Möglichkeit, Variablen und Methoden zu Klassen zusammenzufassen. +Ein weiteres wichtiges Merkmal ist das der Vererbung, also +der Möglichkeit, Eigenschaften vorhandener Klassen auf neue Klassen +zu übertragen. Fehlt diese Fähigkeit, bezeichnet man die +Sprache auch als lediglich objektbasiert. + +

+Man unterscheidet dabei zwischen einfacher Vererbung, +bei der eine Klasse von maximal einer anderen Klasse abgeleitet werden +kann, und Mehrfachvererbung, bei der +eine Klasse von mehr als einer anderen Klasse abgeleitet werden kann. +In Java gibt es lediglich Einfachvererbung, um den Problemen aus dem +Weg zu gehen, die durch Mehrfachvererbung entstehen können. Um +die Einschränkungen in den Designmöglichkeiten, die bei +Einfachvererbung entstehen, zu vermeiden, wurde mit Hilfe der Interfaces +eine neue, restriktive Art der Mehrfachvererbung eingeführt. +Wir werden später darauf zurückkommen. + + + + +

8.1.1 Ableiten einer Klasse

+ +

+Um eine neue Klasse aus einer bestehenden abzuleiten, ist im Kopf +der Klasse mit Hilfe des Schlüsselworts extends +ein Verweis auf die Basisklasse anzugeben. Hierdurch erbt die abgeleitete +Klasse alle Eigenschaften der Basisklasse, d.h. alle Variablen und +alle Methoden. Durch Hinzufügen neuer Elemente oder Überladen +der vorhandenen kann die Funktionalität der abgeleiteten Klasse +erweitert werden. + +

+Als Beispiel wollen wir eine neue Klasse Cabrio +definieren, die sich von Auto +nur dadurch unterscheidet, dass sie zusätzlich die Zeit, die +zum Öffnen des Verdecks benötigt wird, speichern soll: + + +

+ + + + +
+ +
+001 class Cabrio
+002 extends Auto
+003 {
+004   int vdauer;
+005 }
+
+
+ +Listing 8.1: Ein einfaches Beispiel für Vererbung

+ +

+Wir können nun nicht nur auf die neue Variable vdauer, +sondern auch auf alle Elemente der Basisklasse Auto +zugreifen: + + +

+ + + + +
+ +
+001 Cabrio kfz1 = new Cabrio();
+002 kfz1.name = "MX5";
+003 kfz1.erstzulassung = 1994;
+004 kfz1.leistung = 115;
+005 kfz1.vdauer = 120;
+006 System.out.println("Alter = "+kfz1.alter());
+
+
+ +Listing 8.2: Zugriff auf geerbte Membervariablen

+

+ + + + + + + + + +
+ +

+Die Vererbung von Klassen kann beliebig tief geschachtelt werden. +Eine abgeleitete Klasse erbt dabei jeweils die Eigenschaften der unmittelbaren +Vaterklasse, die ihrerseits die Eigenschaften ihrer unmittelbaren +Vaterklasse erbt usw. Wir können also beispielsweise die Klasse +Cabrio verwenden, um daraus +eine neue Klasse ZweisitzerCabrio +abzuleiten:

+ + + + +
 Hinweis 
+
+ + +

+ + + + +
+ +
+001 class ZweisitzerCabrio
+002 extends Cabrio
+003 {
+004   boolean notsitze;
+005 }
+
+
+ +Listing 8.3: Ableitung einer abgeleiteten Klasse

+ +

+Diese könnte nun verwendet werden, um ein Objekt zu instanzieren, +das die Eigenschaften der Klassen Auto, +Cabrio und ZweisitzerCabrio +hat: + + +

+ + + + +
+ +
+001 ZweisitzerCabrio kfz1 = new ZweisitzerCabrio();
+002 kfz1.name = "911-T";
+003 kfz1.erstzulassung = 1982;
+004 kfz1.leistung = 94;
+005 kfz1.vdauer = 50;
+006 kfz1.notsitze = true;
+007 System.out.println("Alter = "+kfz1.alter());
+
+
+ +Listing 8.4: Zugriff auf mehrfach vererbte Membervariablen

+

+ + + + + + + + + +
+ +

+Nicht jede Klasse darf zur Ableitung neuer Klassen verwendet werden. +Besitzt eine Klasse das Attribut final, +ist es nicht erlaubt, eine neue Klasse aus ihr abzuleiten. Die möglichen +Attribute einer Klasse werden im nächsten Abschnitt erläutert.

+ + + + +
 Hinweis 
+
+ + + + +

8.1.2 Die Klasse Object

+ +

+Enthält eine Klasse keine extends-Klausel, +so besitzt sie die implizite Vaterklasse Object. +Jede Klasse, die keine extends-Klausel +besitzt, wird direkt aus Object +abgeleitet. Jede explizit abgeleitete Klasse stammt am oberen Ende +ihrer Vererbungslinie von einer Klasse ohne explizite Vaterklasse +ab und ist damit ebenfalls aus Object +abgeleitet. Object +ist also die Superklasse aller anderen Klassen. + +

+Die Klasse Object +definiert einige elementare Methoden, die für alle Arten von +Objekten nützlich sind: +

+ + + + + +
+ +
+boolean equals(Object obj)
+
+protected Object clone()
+
+String toString()
+
+int hashCode()
+
+
+
+java.lang.Object
+ +

+Die Methode equals +testet, ob zwei Objekte denselben Inhalt haben, clone +kopiert ein Objekt, toString +erzeugt eine String-Repräsentation +des Objekts, und hashCode +berechnet einen numerischen Wert, der als Schlüssel zur Speicherung +eines Objekts in einer Hashtable +verwendet werden kann. Damit diese Methoden in abgeleiteten Klassen +vernünftig funktionieren, müssen sie bei Bedarf überlagert +werden. Für equals +und clone +gilt das insbesondere, wenn das Objekt Referenzen enthält. + + + + +

8.1.3 Überlagern von Methoden

+ +

+Neben den Membervariablen erbt eine abgeleitete Klasse auch die Methoden +ihrer Vaterklasse (wenn dies nicht durch spezielle Attribute verhindert +wird). Daneben dürfen auch neue Methoden definiert werden. Die +Klasse besitzt dann alle Methoden, die aus der Vaterklasse geerbt +wurden, und zusätzlich die, die sie selbst neu definiert hat. + +

+Daneben dürfen auch bereits von der Vaterklasse geerbte Methoden +neu definiert werden. In diesem Fall spricht man von Überlagerung +der Methode. Wurde eine Methode überlagert, wird beim Aufruf +der Methode auf Objekten dieses Typs immer die überlagernde Version +verwendet. + +

+Das folgende Beispiel erweitert die Klasse ZweisitzerCabrio +um die Methode alter, das nun +in Monaten ausgegeben werden soll: + + +

+ + + + +
+ +
+001 class ZweisitzerCabrio
+002 extends Cabrio
+003 {
+004   boolean notsitze;
+005 
+006   public int alter()
+007   {
+008     return 12 * (2000 - erstzulassung);
+009   }
+010 }
+
+
+ +Listing 8.5: Überlagern einer Methode in einer abgeleiteten Klasse

+ +

+Da die Methode alter bereits +aus der Klasse Cabrio geerbt +wurde, die sie ihrerseits von Auto +geerbt hat, handelt es sich um eine Überlagerung. Zukünftig +würde dadurch in allen Objekten vom Typ ZweisitzerCabrio +bei Aufruf von alter die überlagernde +Version, bei allen Objekten des Typs Auto +oder Cabrio aber die ursprüngliche +Version verwendet werden. Es wird immer die Variante aufgerufen, die +dem aktuellen Objekt beim Zurückverfolgen der Vererbungslinie +am nächsten liegt. + + + + +

Dynamische Methodensuche

+ +

+Nicht immer kann bereits der Compiler entscheiden, welche Variante +einer überlagerten Methode er aufrufen soll. In Abschnitt 4.6 +und Abschnitt 7.1.6 wurde +bereits erwähnt, dass das Objekt einer abgeleiteten Klasse zuweisungskompatibel +zu der Variablen einer übergeordneten Klasse ist. Wir dürfen +also beispielsweise ein Cabrio-Objekt +ohne weiteres einer Variablen vom Typ Auto +zuweisen. + +

+Die Variable vom Typ Auto kann +während ihrer Lebensdauer also Objekte verschiedenen Typs enthalten +(insbesondere solche vom Typ Auto, +Cabrio und ZweisitzerCabrio). +Damit kann natürlich nicht schon zur Compile-Zeit entschieden +werden, welche Version einer überlagerten Methode aufgerufen +werden soll. Erst während das Programm läuft, ergibt sich, +welcher Typ von Objekt zu einem bestimmten Zeitpunkt in der Variable +gespeichert wird. Der Compiler muss also Code generieren, um dies +zur Laufzeit zu entscheiden. Man bezeichnet dies auch als dynamisches +Binden. + +

+In C++ wird dieses Verhalten durch virtuelle Funktionen realisiert +und muss mit Hilfe des Schlüsselworts virtual +explizit angeordnet werden. In Java ist eine explizite Deklaration +nicht nötig, denn Methodenaufrufe werden immer dynamisch interpretiert. +Der dadurch verursachte Overhead ist allerdings nicht zu vernachlässigen +und liegt deutlich über den Kosten eines statischen Methodenaufrufs. +Um das Problem zu umgehen, gibt es mehrere Möglichkeiten, dafür +zu sorgen, dass eine Methode nicht dynamisch interpretiert wird. Dabei +wird mit Hilfe zusätzlicher Attribute dafür gesorgt, dass +die betreffende Methode nicht überlagert werden kann: +

+

+ + + + + + + + + +
+ +

+In Abschnitt 8.4 werden +wir das Thema Polymorphismus noch einmal aufgreifen und ein +ausführliches Beispiel für dynamische Methodensuche geben.

+ + + + +
 Hinweis 
+
+ + + + +

Aufrufen einer verdeckten Methode

+ +

+Wird eine Methode x in einer +abgeleiteten Klasse überlagert, wird die ursprüngliche Methode +x verdeckt. Aufrufe von x +beziehen sich immer auf die überlagernde Variante. Oftmals ist +es allerdings nützlich, die verdeckte Superklassenmethode aufrufen +zu können, beispielsweise, wenn deren Funktionalität nur +leicht verändert werden soll. In diesem Fall kann mit Hilfe des +Ausdrucks super.x() +die Methode der Vaterklasse aufgerufen werden. Der kaskadierte Aufruf +von Superklassenmethoden (wie in super.super.x()) +ist nicht erlaubt. + + + + +

8.1.4 Vererbung von Konstruktoren

+ + + + +

Konstruktorenverkettung

+ +

+Wenn eine Klasse instanziert wird, garantiert Java, dass ein zur Parametrisierung +des new-Operators +passender Konstruktor aufgerufen wird. Daneben garantiert der Compiler, +dass auch der Konstruktor der Vaterklasse aufgerufen wird. Dieser +Aufruf kann entweder explizit oder implizit geschehen. + +

+Falls als erste Anweisung innerhalb eines Konstruktors ein Aufruf +der Methode super +steht, wird dies als Aufruf des Superklassenkonstruktors +interpretiert. super +wird wie eine normale Methode verwendet und kann mit oder ohne Parameter +aufgerufen werden. Der Aufruf muss natürlich zu einem in der +Superklasse definierten Konstruktor passen. + +

+Falls als erste Anweisung im Konstruktor kein Aufruf von super +steht, setzt der Compiler an dieser Stelle einen impliziten Aufruf +super(); ein und ruft damit +den parameterlosen Konstruktor der Vaterklasse auf. Falls ein solcher +Konstruktor in der Vaterklasse nicht definiert wurde, gibt es einen +Compiler-Fehler. Das ist genau dann der Fall, wenn in der Superklassendeklaration +lediglich parametrisierte Konstruktoren angegeben wurden und +daher ein parameterloser default-Konstruktor nicht automatisch +erzeugt wurde. +

+ + + + + + + + + +
+ +

+Alternativ zu diesen beiden Varianten, einen Superklassenkonstruktor +aufzurufen, ist es auch erlaubt, mit Hilfe der this-Methode +einen anderen Konstruktor der eigenen Klasse aufzurufen. Um die oben +erwähnten Zusagen einzuhalten, muss dieser allerdings selbst +direkt oder indirekt schließlich einen Superklassenkonstruktor +aufrufen.

+ + + + +
 Hinweis 
+
+ + + + +

Der Default-Konstruktor

+ +

+Das Anlegen von Konstruktoren in einer Klasse ist optional. Falls +in einer Klasse überhaupt kein Konstruktor definiert wurde, erzeugt +der Compiler beim Übersetzen der Klasse automatisch einen parameterlosen +default-Konstruktor. Dieser enthält lediglich einen Aufruf +des parameterlosen Superklassenkonstruktors. + + + + +

Überlagerte Konstruktoren

+

+ + + + + + + + + +
+ +

+Konstruktoren werden nicht vererbt. Alle Konstruktoren, die in einer +abgeleiteten Klasse benötigt werden, müssen neu definiert +werden, selbst wenn sie nur aus einem Aufruf des Superklassenkonstruktors +bestehen.

+ + + + +
 Hinweis 
+
+ +

+Durch diese Regel wird bei jedem Neuanlegen eines Objekts eine ganze +Kette von Konstruktoren aufgerufen. Da nach den obigen Regeln jeder +Konstruktor zuerst den Superklassenkonstruktor aufruft, wird die Initialisierung +von oben nach unten in der Vererbungshierarchie durchgeführt: +zuerst wird der Konstruktor der Klasse Object +ausgeführt, dann der der ersten Unterklasse usw., bis zuletzt +der Konstruktor der zu instanzierenden Klasse ausgeführt wird. + + + + +

Destruktorenverkettung

+

+ + + + + + + + + +
+ +

+Im Gegensatz zu den Konstruktoren werden die Destruktoren eines Ableitungszweiges +nicht automatisch verkettet. Falls eine Destruktorenverkettung erforderlich +ist, kann sie durch explizite Aufrufe des Superklassendestruktors +mit Hilfe der Anweisung super.finalize() +durchgeführt werden.

+ + + + +
 Hinweis 
+
+


+ + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 +
 <<  +  <   +  >   + >>  + API  +© 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de +
+ + + -- cgit v1.2.3