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/k100049.html | 1135 ++++++++++++++++++++ 1 file changed, 1135 insertions(+) create mode 100644 Master/Reference Architectures and Patterns/hjp5/html/k100049.html (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100049.html') diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100049.html b/Master/Reference Architectures and Patterns/hjp5/html/k100049.html new file mode 100644 index 0000000..09f810d --- /dev/null +++ b/Master/Reference Architectures and Patterns/hjp5/html/k100049.html @@ -0,0 +1,1135 @@ + + + +Handbuch der Java-Programmierung, 5. Auflage + + + + + + + + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage +
 <<  +  <   +  >   + >>  + API  +Kapitel 7 - OOP I: Grundlagen +
+
+ + + + +

7.3 Methoden

+
+ +
+ + + + +

7.3.1 Definition

+ +

+Methoden definieren das Verhalten von Objekten. Sie werden +innerhalb einer Klassendefinition angelegt und haben Zugriff auf alle +Variablen des Objekts. Methoden sind das Pendant zu den Funktionen +anderer Programmiersprachen, arbeiten aber immer mit den Variablen +des aktuellen Objekts. Globale Funktionen, +die vollkommen unabhängig von einem Objekt oder einer Klasse +existieren, gibt es in Java ebensowenig wie globale Variablen. Wir +werden später allerdings Klassenvariablen und -methoden kennenlernen, +die nicht an eine konkrete Instanz gebunden sind. + +

+Die Syntax der Methodendefinition in Java ähnelt der von C/C++: +

+ + + + +
+ +
+{Modifier}
+Typ Name([Parameter])
+{
+  {Anweisung;}
+}
+
+
+
+ +

+Nach einer Reihe von Modifiern (wir +kommen weiter in Abschnitt 8.2 +darauf zurück) folgen der Typ des Rückgabewerts der +Funktion, ihr Name und eine optionale Parameterliste. +In geschweiften Klammern folgt dann der Methodenrumpf, also +die Liste der Anweisungen, die das Verhalten der Methode festlegen. +Die Erweiterung unserer Beispielklasse um eine Methode zur Berechnung +des Alters des Auto-Objekts +würde beispielsweise so aussehen: + + +

+ + + + +
+ +
+001 public class Auto
+002 {
+003   public String name;
+004   public int    erstzulassung;
+005   public int    leistung;
+006 
+007   public int alter()
+008   {
+009     return 2000 - erstzulassung;
+010   }
+011 }
+
+
+ +Listing 7.6: Eine einfache Methode zur Altersberechnung

+ +

+Hier wird eine Methode alter +definiert, die einen ganzzahligen Wert zurückgibt, der sich aus +der Differenz des Jahres 2000 und dem Jahr der Erstzulassung errechnet. + + + + +

7.3.2 Aufruf

+ +

+Der Aufruf einer Methode erfolgt ähnlich der Verwendung einer +Instanzvariablen in Punktnotation. Zur Unterscheidung von einem Variablenzugriff +müssen zusätzlich die Parameter der Methode in Klammern +angegeben werden, selbst wenn die Liste leer ist. Das folgende Programm +würde demnach die Zahl 10 auf dem Bildschirm ausgeben. + + +

+ + + + +
+ +
+001 Auto golf1 = new Auto();
+002 golf1.erstzulassung = 1990;
+003 System.out.println(golf1.alter());
+
+
+ +Listing 7.7: Aufruf einer Methode

+

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

+Wie an der Definition von alter +zu erkennen ist, darf eine Methode auf die Instanzvariablen ihrer +Klasse zugreifen, ohne die Punktnotation zu verwenden. Das funktioniert +deshalb, weil der Compiler alle nicht in Punktnotation verwendeten +Variablen x, die nicht lokale +Variablen sind, auf das Objekt this +bezieht und damit als this.x +interpretiert.

+ + + + +
 Tipp 
+
+ +

+Bei this +handelt es sich um einen Zeiger, der beim Anlegen eines Objekts automatisch +generiert wird. this +ist eine Referenzvariable, die auf das aktuelle Objekt zeigt und dazu +verwendet wird, die eigenen Methoden und Instanzvariablen anzusprechen. +Der this-Zeiger +ist auch explizit verfügbar und kann wie eine ganz normale +Objektvariable verwendet werden. Er wird als versteckter Parameter +an jede nicht-statische Methode übergeben. Die Methode alter +hätte also auch so geschrieben werden können: + + +

+ + + + +
+ +
+001 public int alter()
+002 {
+003   return 2000 - this.erstzulassung;
+004 }
+
+
+ +Listing 7.8: Verwendung von this

+

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

+Manchmal ist es sinnvoll, this +explizit zu verwenden, auch wenn es nicht unbedingt erforderlich ist. +Dadurch wird hervorgehoben, dass es sich um den Zugriff auf eine Instanzvariable, +und nicht eine lokale Variable, handelt.

+ + + + +
 Tipp 
+
+ + + + +

7.3.3 Parameter

+ +

+Eine Methode kann mit Parametern definiert werden. Dazu wird bei der +Methodendefinition eine Parameterliste innerhalb der Klammern angegeben. +Jeder formale Parameter besteht aus einem Typnamen und dem Namen des +Parameters. Soll mehr als ein Parameter definiert werden, so sind +die einzelnen Definitionen durch Kommata zu trennen. + +

+Alle Parameter werden in Java per call by value +übergeben. Beim Aufruf einer Methode wird also der aktuelle Wert +in die Parametervariable kopiert und an die Methode übergeben. +Veränderungen der Parametervariablen innerhalb der Methode bleiben +lokal und wirken sich nicht auf den Aufrufer aus. Das folgende Beispiel +definiert eine Methode printAlter, +die das Alter des Autos insgesamt wieoft +mal auf dem Bildschirm ausgibt: + + +

+ + + + +
+ +
+001 public void printAlter(int wieoft)
+002 {
+003   while (wieoft-- > 0) {
+004     System.out.println("Alter = " + alter());
+005   }
+006 }
+
+
+ +Listing 7.9: Eine Methode zur Ausgabe des Alters

+ +

+Obwohl der Parameter wieoft +innerhalb der Methode verändert wird, merkt ein Aufrufer nichts +von diesen Änderungen, da innerhalb der Methode mit einer Kopie +gearbeitet wird. Das folgende Programm würde das Alter des Objekts +auto daher insgesamt neunmal +auf dem Bildschirm ausgeben: + + +

+ + + + +
+ +
+001 ...
+002 int a = 3;
+003 
+004 auto.printAlter(a);
+005 auto.printAlter(a);
+006 auto.printAlter(a);
+007 ...
+
+
+ +Listing 7.10: Wiederholter Aufruf der Methode zur Ausgabe des Alters

+ +

+Wie bereits erwähnt, sind Objektvariablen Referenzen, also Zeiger. +Zwar werden auch sie bei der Übergabe an eine Methode per Wert +übergeben. Da innerhalb der Methode aber der Zeiger auf das Originalobjekt +zur Verfügung steht (wenn auch in kopierter Form), wirken sich +Veränderungen an dem Objekt natürlich direkt auf das Originalobjekt +aus und sind somit für den Aufrufer der Methode sichtbar. Wie +in allen anderen Programmiersprachen entspricht die call by value-Übergabe +eines Zeigers damit natürlich genau der Semantik von call +by reference. +

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

+Die Übergabe von Objekten an Methoden hat damit zwei wichtige +Konsequenzen: +

    +
  • Die Methode erhält keine Kopie, sondern arbeitet mit dem +Originalobjekt. +
  • Die Übergabe von Objekten ist performant, gleichgültig +wie groß sie sind. +
+
+ + + + +
 Hinweis 
+
+ +

+Sollen Objekte kopiert werden, so muss dies explizit durch Aufruf +der Methode clone +der Klasse Object +erfolgen. +

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

+Die Übergabe von Objekten und Arrays per Referenz kann leicht +zu verdeckten Fehlern führen. Da die aufgerufene Methode mit +dem Originalobjekt arbeitet, kann sie deren Membervariablen bzw. Elemente +verändern, ohne dass der Aufrufer es merkt. Auch der final-Modifier +(siehe Abschnitt 8.2) bietet dagegen +keinen Schutz. Das unbeabsichtigte Ändern einer modifizierbaren +Referenzvariable bei der Übergabe an eine Methode kann nur durch +vorheriges Kopieren verhindert werden.

+ + + + +
 Warnung 
+
+ + + + +

7.3.4 Variable Parameterlisten +

+

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

+Seit Java 5 gibt es die Möglichkeit, variable Parameterlisten +zu definieren, in denen ein formaler Parameter für eine beliebige +Anzahl aktueller Argumente steht. Dazu kann der letzte Parameter einer +Methode (und nur dieser) nach dem Typbezeichner mit drei Punkten versehen +werden. So wird angezeigt, dass an dieser Stelle beim Aufruf eine +beliebige Anzahl Argumente des passenden Typs übergeben werden +darf: + + +

+ + + + +
+ +
+001 public static void printArgs(String... args)
+002 {
+003   for (int i = 0; i < args.length; ++i) {
+004     System.out.println(args[i]);
+005   }
+006 }
+
+
+ +Listing 7.11: Eine Methode mit einer variablen Parameterliste

+
+ + + + +
 JDK1.1-6.0 
+
+ +

+Technisch entspricht die Deklaration der eines Arrays-Parameters, +und so wird auch auf die Elemente zugegriffen. Die Vereinfachung wird +sichtbar, wenn man sich den Aufruf der Methode ansieht. An +dieser Stelle darf nämlich nicht nur ein einzelnes Array übergeben +werden, sondern die einzelnen Elemente können auch separat angegeben +werden. Dabei erzeugt das Laufzeitsystem automatisch ein Array, in +das diese Werte übertragen werden. Die beiden folgenden Aufrufe +sind also gleichwertig: + +

+printArgs(new String[]{"so", "wird", "es", "gemacht"});
+
+printArgs("so", "wird", "es", "gemacht");
+
+ + +

+Nun wird auch deutlich, warum lediglich der letzte Parameter variabel +sein darf. Andernfalls könnte der Compiler unter Umständen +nicht mehr unterscheiden, welches aktuelle Argument zu welchem formalen +Parameter gehört. + +

+Praktischen Nutzen haben die variablen Parameterlisten bei Anwendungen, +in denen nicht von vorneherein klar ist, wieviele Argumente benötigt +werden. Tatsächlich wurde ihre Entwicklung durch den Wunsch motiviert, +flexible Ausgabemethoden definieren zu können, wie sie etwa in +C/C++ mit der printf-Familie zur Verfügung stehen (und seit der +J2SE 5.0 mit der Klasse java.util.Formatter, +die in Abschnitt 11.6 +beschrieben wird). Sie können dann die in diesem Fall vielfach +verwendeten überladenen Methoden ersetzen (siehe Abschnitt 7.3.6). +Natürlich benötigt nicht jede Methode variable Parameterlisten, +sondern ihre Anwendung sollte auf Spezialfälle beschränkt +bleiben. + +

+Wird eine Methode mit einem Parameter vom Typ Object... +deklariert, entstehen in Zusammenhang mit dem ebenfalls seit der J2SE +5.0 verfügbaren Mechanismus des Autoboxings (siehe Abschnitt 10.2.3) +Methoden, bei denen praktisch alle Typprüfungen des Compilers +ausgehebelt werden. Da ein Element des Typs Object +zu allen anderen Referenztypen kompatibel ist und primitive Typen +dank des Autoboxings automatisch in passende Wrapper-Objekte konvertiert +werden, kann an einen Parameter des Typs Object... +eine beliebige Anzahl beliebiger Argumente übergeben werden. + +

+Das folgende Listing zeigt eine Methode, die numerische Argumente +jeweils solange summiert, bis ein nichtnumerischer Wert übergeben +wird. Dieser wird dann in einen String konvertiert und zusammen mit +der Zwischensumme ausgegeben. Am Ende wird zusätzlich die Gesamtsumme +ausgegeben. Nicht unbedingt eine typische Anwendung, und erst recht +kein empfehlenswerter Programmierstil, aber das Listing demonstriert, +wie weitreichend die Möglichkeiten dieses neuen Konzepts sind: + + +

+ + + + + +
+ +
+001 /* Listing0712.java */
+002 
+003 public class Listing0712
+004 {
+005   public static void registrierKasse(Object... args)
+006   {
+007     double zwischensumme = 0;
+008     double gesamtsumme   = 0;
+009     for (int i = 0; i < args.length; ++i) {
+010       if (args[i] instanceof Number) {
+011         zwischensumme += ((Number)args[i]).doubleValue();
+012       } else {
+013         System.out.println(args[i] + ": " + zwischensumme);
+014         gesamtsumme += zwischensumme;
+015         zwischensumme = 0;
+016       }
+017     }
+018     System.out.println("Gesamtsumme: " + gesamtsumme);
+019   }
+020 
+021   public static void main(String[] args)
+022   {
+023     registrierKasse(
+024       1.45, 0.79, 19.90, "Ware",
+025       -3.00, 1.50, "Pfand",
+026       -10, "Gutschein"
+027     );
+028   }
+029 }
+
+
+Listing0712.java
+ +Listing 7.12: Die Anwendung von Object...

+ +

+Die Ausgabe des Programms ist: + +

+Ware: 22.14
+Pfand: -1.5
+Gutschein: -10.0
+Gesamtsumme: 10.64
+
+ + + + + +

7.3.5 Rückgabewert

+ +

+Jede Methode in Java ist typisiert. Der Typ einer Methode wird zum +Zeitpunkt der Definition festgelegt und bestimmt den Typ des Rückgabewerts. +Dieser kann von einem beliebigen primitiven Typ, einem Objekttyp (also +einer Klasse) oder vom Typ void +sein. Die Methoden vom Typ void +haben gar keinen Rückgabewert und dürfen nicht in Ausdrücken +verwendet werden. Sie sind lediglich wegen ihrer Nebeneffekte von +Interesse und dürfen daher nur als Ausdrucksanweisung verwendet +werden. + +

+Hat eine Methode einen Rückgabewert (ist also nicht vom Typ void), +so kann sie mit Hilfe der return-Anweisung +einen Wert an den Aufrufer zurückgeben. Die return-Anweisung +hat folgende Syntax: +

+ + + + +
+ +
+return Ausdruck;
+
+
+
+ +

+Wenn diese Anweisung ausgeführt wird, führt dies zum Beenden +der Methode, und der Wert des angegebenen Ausdrucks wird an den Aufrufer +zurückgegeben. Der Ausdruck muss dabei zuweisungskompatibel zum +Typ der Funktion sein. Die in Kapitel 5 +erläuterte Datenflussanalyse sorgt dafür, dass hinter der +return-Anweisung +keine unerreichbaren Anweisungen stehen und dass jeder mögliche +Ausgang einer Funktion mit einem return +versehen ist. Der in C beliebte Fehler, einen Funktionsausgang ohne +return-Anweisung +zu erzeugen (und damit einen undefinierten Rückgabewert zu erzeugen), +kann in Java also nicht passieren. + + + + +

7.3.6 Überladen von Methoden

+ +

+In Java ist es erlaubt, Methoden zu überladen, d.h. innerhalb +einer Klasse zwei unterschiedliche Methoden mit demselben Namen zu +definieren. Der Compiler unterscheidet die verschiedenen Varianten +anhand der Anzahl und der Typisierung ihrer Parameter. Haben zwei +Methoden denselben Namen, aber unterschiedliche Parameterlisten, werden +sie als verschieden angesehen. Es ist dagegen nicht erlaubt, zwei +Methoden mit exakt demselben Namen und identischer Parameterliste +zu definieren. + +

+Der Rückgabetyp einer Methode trägt nicht zu ihrer Unterscheidung +bei. Zwei Methoden, die sich nur durch den Typ ihres Rückgabewertes +unterscheiden, werden also als gleich angesehen. Da Methoden auch +ohne die Verwendung ihres Rückgabewerts aufgerufen werden können +(was typischerweise wegen ihrer Nebeneffekte geschieht), hätte +weder der Compiler noch der menschliche Leser in diesem Fall die Möglichkeit, +festzustellen, welche der überladenen Varianten tatsächlich +aufgerufen werden soll. +

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

+Das Überladen von Methoden ist dann sinnvoll, wenn die gleichnamigen +Methoden auch eine vergleichbare Funktionalität haben. Eine typische +Anwendung von überladenen Methoden besteht in der Simulation +von variablen Parameterlisten (die als Feature erst seit der Version +5.0 zur Verfügung stehen). Auch, um eine Funktion, die bereits +an vielen verschiedenen Stellen im Programm aufgerufen wird, um einen +weiteren Parameter zu erweitern, ist es nützlich, diese Funktion +zu überladen, um nicht alle Aufrufstellen anpassen zu müssen.

+ + + + +
 Tipp 
+
+ +

+Das folgende Beispiel erweitert die Klasse Auto +um eine weitere Methode alter, +die das Alter des Autos nicht nur zurückgibt, sondern es auch +mit einem als Parameter übergebenen Titel versieht und auf dem +Bildschirm ausgibt: + + +

+ + + + +
+ +
+001 public int alter(String titel)
+002 {
+003   int alter = alter();
+004   System.out.println(titel+alter);
+005   return alter;
+006 }
+
+
+ +Listing 7.13: Überladen einer Methode

+ + + + +

Die Signatur einer Methode

+ +

+Innerhalb dieser Methode wird der Name alter +in drei verschiedenen Bedeutungen verwendet. Erstens ist alter +der Name der Methode selbst. Zweitens wird die lokale Variable alter +definiert, um drittens den Rückgabewert der parameterlosen alter-Methode +aufzunehmen. Der Compiler kann die Namen in allen drei Fällen +unterscheiden, denn er arbeitet mit der Signatur der Methode. +Unter der Signatur einer Methode versteht man ihren internen +Namen. Dieser setzt sich aus dem nach außen sichtbaren Namen +plus codierter Information über die Reihenfolge und Typen der +formalen Parameter zusammen. Die Signaturen zweier gleichnamiger Methoden +sind also immer dann unterscheidbar, wenn sie sich wenigstens in einem +Parameter voneinander unterscheiden. + + + + +

7.3.7 Konstruktoren

+ +

+In jeder objektorientierten Programmiersprache lassen sich spezielle +Methoden definieren, die bei der Initialisierung eines Objekts aufgerufen +werden: die Konstruktoren. In Java werden Konstruktoren als +Methoden ohne Rückgabewert definiert, die den Namen der Klasse +erhalten, zu der sie gehören. Konstruktoren dürfen eine +beliebige Anzahl an Parametern haben und können überladen +werden. Die Erweiterung unserer Auto-Klasse +um einen Konstruktor, der den Namen des Auto-Objekts +vorgibt, sieht beispielsweise so aus: + + +

+ + + + +
+ +
+001 public class Auto
+002 {
+003   public String name;
+004   public int    erstzulassung;
+005   public int    leistung;
+006 
+007   public Auto(String name)
+008   {
+009     this.name = name;
+010   }
+011 }
+
+
+ +Listing 7.14: Definition eines parametrisierten Konstruktors

+ +

+Soll ein Objekt unter Verwendung eines parametrisierten Konstruktors +instanziert werden, so sind die Argumente wie bei einem Methodenaufruf +in Klammern nach dem Namen des Konstruktors anzugeben: + + +

+ + + + +
+ +
+001 Auto dasAuto = new Auto("Porsche 911");
+002 System.out.println(dasAuto.name);
+
+
+ +Listing 7.15: Aufruf eines parametrisierten Konstruktors

+ +

+In diesem Fall wird zunächst Speicher für das Auto-Objekt +beschafft und dann der Konstruktor aufgerufen. Dieser initialisiert +seinerseits die Instanzvariable name +mit dem übergebenen Argument »Porsche 911«. Der nachfolgende +Aufruf schreibt dann diesen Text auf den Bildschirm. +

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

+Explizite Konstruktoren werden immer dann eingesetzt, wenn zur Initialisierung +eines Objektes besondere Aufgaben zu erledigen sind. Es ist dabei +durchaus gebräuchlich, Konstruktoren zu überladen und mit +unterschiedlichen Parameterlisten auszustatten. Beim Ausführen +der new-Anweisung +wählt der Compiler anhand der aktuellen Parameterliste den passenden +Konstruktor und ruft ihn mit den angegebenen Argumenten auf.

+ + + + +
 Tipp 
+
+ +

+Wir wollen das vorige Beispiel um einen Konstruktor erweitern, der +alle Instanzvariablen initialisiert: + + +

+ + + + +
+ +
+001 public class Auto
+002 {
+003   public String name;
+004   public int    erstzulassung;
+005   public int    leistung;
+006 
+007   public Auto(String name)
+008   {
+009     this.name = name;
+010   }
+011 
+012   public Auto(String name,
+013               int    erstzulassung,
+014               int    leistung)
+015   {
+016     this.name = name;
+017     this.erstzulassung = erstzulassung;
+018     this.leistung = leistung;
+019   }
+020 }
+
+
+ +Listing 7.16: Eine Klasse mit mehreren Konstruktoren

+ + + + +

Default-Konstruktoren

+ +

+Falls eine Klasse überhaupt keinen expliziten Konstruktor +besitzt, wird vom Compiler automatisch ein parameterloser default-Konstruktor +generiert. Seine einzige Aufgabe besteht darin, den parameterlosen +Konstruktor der Superklasse aufzurufen. Enthält eine Klassendeklaration +dagegen nur parametrisierte Konstruktoren, wird kein default-Konstruktor +erzeugt, und die Klassendatei besitzt überhaupt keinen parameterlosen +Konstruktor. + + + + +

Verkettung von Konstruktoren +

+ +

+Unterschiedliche Konstruktoren einer Klasse können in Java verkettet +werden, d.h. sie können sich gegenseitig aufrufen. Der aufzurufende +Konstruktor wird dabei als eine normale Methode angesehen, die über +den Namen this +aufgerufen werden kann. Die Unterscheidung zum bereits vorgestellten +this-Pointer +nimmt der Compiler anhand der runden Klammern vor, die dem Aufruf +folgen. Der im vorigen Beispiel vorgestellte Konstruktor hätte +damit auch so geschrieben werden können: + + +

+ + + + +
+ +
+001 public Auto(String name,
+002             int    erstzulassung,
+003             int    leistung)
+004 {
+005   this(name);
+006   this.erstzulassung = erstzulassung;
+007   this.leistung = leistung;
+008 }
+
+
+ +Listing 7.17: Verkettung von Konstruktoren

+

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

+Der Vorteil der Konstruktorenverkettung besteht darin, dass vorhandener +Code wiederverwendet wird. Führt ein parameterloser Konstruktor +eine Reihe von nichttrivialen Aktionen durch, so ist es natürlich +sinnvoller, diesen in einem spezialisierteren Konstruktor durch Aufruf +wiederzuverwenden, als den Code zu duplizieren.

+ + + + +
 Hinweis 
+
+

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

+Wird ein Konstruktor in einem anderen Konstruktor derselben Klasse +explizit aufgerufen, muss dies als erste Anweisung innerhalb der Methode +geschehen. Steht der Aufruf nicht an erster Stelle, gibt es +einen Compiler-Fehler.

+ + + + +
 Warnung 
+
+ +

+Es gibt noch eine zweite Form der Konstruktorenverkettung. Sie findet +automatisch statt und dient dazu, abgeleitete Klassen während +der Instanzierung korrekt zu initialisieren. In Abschnitt 8.1.4 +werden wir auf die Details dieses Mechanismus eingehen. + + + + +

Initialisierungsreihenfolge

+ +

+Beim Instanzieren eines neuen Objekts werden die Initialisierungschritte +in einer genau festgelegten Reihenfolge ausgeführt: +

+ +

+Wir wollen dies an einem Beispiel veranschaulichen: + + +

+ + + + + +
+ +
+001 /* Listing0718.java */
+002 
+003 public class Listing0718
+004 {
+005   public static String getAndPrint(String s)
+006   {
+007     System.out.println(s);
+008     return s;
+009   }
+010 
+011   public static void main(String[] args)
+012   {
+013     Son son = new Son();
+014   }
+015 }
+016 
+017 class Father
+018 {
+019   private String s1 = Listing0718.getAndPrint("Father.s1");
+020 
+021   public Father()
+022   {
+023     Listing0718.getAndPrint("Father.<init>");
+024   }
+025 }
+026 
+027 class Son
+028 extends Father
+029 {
+030   private String s1 = Listing0718.getAndPrint("Son.s1");
+031 
+032   public Son()
+033   {
+034     Listing0718.getAndPrint("Son.<init>");
+035   }
+036 }
+
+
+Listing0718.java
+ +Listing 7.18: Initialisierungsreihenfolge

+ +

+Im Hauptprogramm wird eine neue Instanz der Klasse Son +angelegt. Durch die Konstruktorenverkettung wird zunächst zur +Vaterklasse Father verzweigt. +Darin wird zunächst die Membervariable s1 +initialisiert, und anschließend wird der Rumpf des Konstruktors +ausgeführt. Erst danach führt Son +dieselben Schritte für sich selbst durch. Die Ausgabe des Programms +ist demnach: + +

+Father.s1
+Father.<init>
+Son.s1
+Son.<init>
+
+ + + + + +

7.3.8 Destruktoren

+ +

+Neben Konstruktoren, die während der Initialisierung eines Objekts +aufgerufen werden, gibt es in Java auch Destruktoren. Sie werden +unmittelbar vor dem Zerstören eines Objekts aufgerufen. + +

+Ein Destruktor wird als geschützte (protected) +parameterlose Methode mit dem Namen finalize +definiert: + + +

+ + + + +
+ +
+001 protected void finalize()
+002 {
+003   ...
+004 }
+
+
+ +Listing 7.19: Die finalize-Methode

+

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

+Da Java über ein automatisches Speichermanagement verfügt, +kommt den Destruktoren hier eine viel geringere Bedeutung zu als in +anderen objektorientierten Sprachen. Anders als etwa in C++ muss sich +der Entwickler ja nicht um die Rückgabe von belegtem Speicher +kümmern; und das ist sicher eine der Hauptaufgaben von Destruktoren +in C++.

+ + + + +
 Hinweis 
+
+ +

+Tatsächlich garantiert die Sprachspezifikation nicht, dass ein +Destruktor überhaupt aufgerufen wird. Wenn er aber aufgerufen +wird, so erfolgt dies nicht, wenn die Lebensdauer des Objektes endet, +sondern dann, wenn der Garbage Collector den für das Objekt reservierten +Speicherplatz zurückgibt. Dies kann unter Umständen nicht +nur viel später der Fall sein (der Garbage Collector läuft +ja als asynchroner Hintergrundprozess), sondern auch gar nicht. Wird +nämlich das Programm beendet, bevor der Garbage Collector das +nächste Mal aufgerufen wird, werden auch keine Destruktoren aufgerufen. +Selbst wenn Destruktoren aufgerufen werden, ist die Reihenfolge oder +der Zeitpunkt ihres Aufrufs undefiniert. Der Einsatz von Destruktoren +in Java sollte also mit der nötigen Vorsicht erfolgen. +


+ + + +
 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