MarktundTechnik Home-Page Previous Page TOC Index Next Page See Page



7. Tag:

Mehr über Methoden

von Laura Lemay

Methoden zählen zu den wichtigsten Teilen jeder objektorientierten Sprache. Während Klassen und Objekte den Rahmen bilden und Klassen- und Instanzvariablen Attribute und Zustände dieser Klasse oder Objekte aufnehmen, sind es die Methoden, die das Verhalten eines Objekts bestimmen und definieren, wie ein Objekt mit anderen im System interagiert.

Gestern haben Sie ein wenig über das Definieren von Methoden gelernt. Mit diesem Grundwissen können Sie bereits verschiedene Java-Programme schreiben, jedoch würden ihnen einige Merkmale von Methoden fehlen, durch die Java-Programme erst richtig leistungsstark werden. Durch sie werden Ihre Objekte und Klassen effizienter und übersichtlicher. Heute lernen Sie alles über diese zusätzlichen Merkmale, darunter:

Methoden mit dem gleichen Namen, aber anderen Argumenten erstellen

Gestern haben Sie gelernt, wie Methoden mit einem Namen und einer Unterschrift erstellt werden. In Java können Methoden darüber hinaus auch »überladen« werden. Das bedeutet, daß Sie Methoden mit dem gleichen Namen, jedoch anderen Unterschriften und anderen Definitionen erstellen können. Durch Methoden-Overloading können Instanzen einer Klasse eine einfachere Schnittstelle auf andere Objekte haben (keine Notwendigkeit für völlig unterschiedliche Methoden, die im Grunde das gleiche bewirken) und sich je nach Eingabe in die Methode anders verhalten.

Beim Aufrufen einer Methode in einem Objekt stimmt Java den Methodennamen sowie Zahl und Typ der Argumente ab, um zu ermitteln, welche Methodendefinition auszuführen ist.

Um eine Methode zu überladen, legen Sie lediglich mehrere unterschiedliche Methodendefinitionen in einer Klasse an, die alle den gleichen Namen, jedoch unterschiedliche Parameter (entweder in bezug auf die Zahl oder den Typ der Argumente) und andere Körper haben. Java erkennt das Methoden-Overloading daran, daß jede Parameterliste für jeden Methodennamen eindeutig ist.

Java unterscheidet Overloading-Methoden mit dem gleichen Namen anhand der Zahl und des Typs von Parameters für die jeweilige Methode, nicht anhand der Ausgabeart. Das heißt, wenn Sie zwei Methoden mit dem gleichen Namen, der gleichen Parameterliste, jedoch unterschiedlichen Ausgabearten erstellen, erhalten Sie einen Kompilierfehler. Die für jeden Parameter einer Methode gewählten Variablennamen sind nicht relevant, nur die Zahl und der Typ zählen.

Im folgenden Beispiel wird eine Overloading-Methode erstellt. Listing 7.1 zeigt eine einfache Klassendefinition für die Klasse MyRect, die eine rechteckige Form definiert. Die Klasse MyRect hat vier Instanzvariablen, die die obere linke und untere rechte Ecke des Rechtecks definieren: x1, y1, x2 und y2.

Warum ich die Klasse MyRect genannt habe? Im awt-Paket von Java ist eine Klasse namens Rectangle enthalten, die einen Großteil des gleichen Verhaltens implementiert. Um zu vermeiden, daß die zwei Klassen verwechselt werden, habe ich diese Klasse MyRect genannt.

Listing 7.1: Die MyRect-Klasse

class MyRect {


int x1 = 0;
int y1 = 0;
int x2 = 0;
int y2 = 0;
}

Wird eine neue Instanz von der Klasse MyRect erstellt, werden alle ihre Instanzvariablen auf 0 initialisiert. Wir definieren nun die Methode buildRect(), die die Größe des Rechtecks anhand von vier Integer-Argumenten auf die entsprechenden Werte abändert, so daß das Reckteckobjekt richtig ausgegeben wird (da die Argumente den gleichen Namen als Instanzvariablen haben, müssen Sie sicherstellen, daß auf sie mit this verwiesen wird):

MyRect buildRect (int x1, int y1, int x2, int y2) {

   this.x1 = x1;

   this.y1 = y1;

   this.x2 = x2;

   this.y2 = y2;

   return this;

}

Was nun, wenn man andere Dimensionen für das Rechteck definieren will, z. B. durch Verwendung von Point-Objekten anstelle der einzelnen Koordinaten? In diesem Fall überladen Sie buildRect(), so daß dessen Parameterliste zwei Point-Objekte erhält (Sie müssen die Point-Klasse an den Anfang Ihrer Quelldatei importieren, damit Java sie findet):

MyRect buildRect (Point topLeft, Point bottomRight) {

   x1 = topLeft.x;

   y1 = topLeft.y;

   x2 = bottomRight.x;

   y2 = bottomRight.y;

   return this;

}

Eventuell möchten Sie das Rechteck mit einer oberen Ecke sowie einer bestimmten Breite und Höhe definieren. Hierfür schreiben Sie einfach eine andere Definition für buildRect():

MyRect buildRect (Point topLeft, int w, int h) {

   x1 = topLeft.x;

   y1 = topLeft.y;

   x2 = (x1 + w);

   y2 = (y1 + h);

   return this;

}

Um dieses Beispiel zu beenden, erstellen wir eine Methode zum Ausgeben der Koordinaten des Recktecks und eine main()-Methode zum Testen aller Werte (einfach um zu beweisen, daß das tatsächlich funktioniert). Listing 7.2 zeigt die fertige Klassendefinition mit allen Methoden.

Listing 7.2: Die fertige MyRect-Klasse

import java.awt.Point;

class MyRect {

   int x1 = 0;

   int y1 = 0;

   int x2 = 0;

   int y2 = 0;



   MyRect buildRect (int x1, int y1, int x2, int y2) {

      this.x1 = x1;

      this.y1 = y1;

      this.x2 = x2;

      this.y2 = y2;

      return this;

   }

   MyRect buildRect(Point topLeft, Point bottomRight) {

      x1 = topLeft.x;

      y1 = topLeft.y;

      x2 = bottomRight.x;

      y2 = bottomRight.y;

      return this;

   }

   MyRect buildRect(Point topLeft, int w, int h) {

      x1 = topLeft.x;

      y1 = topLeft.y;

      x2 = (x1 + w);

      y2 = (y1 + h);

      return this;

   }

   void printRect() {

      System.out.print("MyRect: "= + x1 + ", " + y1);

      System.out.println(", " + x2 + ", " + y2 + ">");

   }

   public static void main (String args[]) {

      MyRect rect = new MyRect();



      System.out.println("Calling buildRect with coordinates 25,25 50,50:");

      rect.buildRect(25, 25, 50, 50);

      rect.printRect();

      System.out.println("- - - - - - - - - -");



      System.out.println("Calling buildRect w/points (10,10), (20,20):");

      rect.buildRect(new Point(10,10), new Point(20,20));

      rect.printRect();

      System.out.println("- - - - - - - - - -");



      System.out.print("Calling buildRect w/1 point (10,10),");

      System.out.println(" width (50) and height (50)");



      rect.buildRect(new Point(10,10), 50, 50);

      rect.printRect();

      System.out.println("- - - - - - - - - -");

   }

}

Die Ausgabe dieses Java-Programms ist wie folgt:

Calling buildRect with coordinates 25,25 50,50:

MyRect: <25, 25, 50, 50>

- - - - - - - - - -

Calling buildRect w/points (10,10), (20,20):

MyRect: <10, 10, 20, 20>

- - - - - - - - - -

Calling buildRect w/1 point (10,10), width (50) and height (50)

MyRect: <10, 10, 60, 60>

- - - - - - - - - -

Wie Sie an diesem Beispiel sehen, funktionieren alle buildRect()-Methoden auf der Grundlage der Argumente, mit denen sie aufgerufen werden. Sie können in Ihren Klassen beliebig viele Versionen einer Methode definieren, um das für die jeweilige Klasse benötigte Verhalten zu implementieren.

Constructor-Methoden

Zusätzlich zu den üblichen Methoden können Sie in einer Klassendefinition auch Constructor-Methoden definieren.

Eine Constructor-Methode ist eine besondere Methodenart, die beim Erstellen bestimmt, wie ein Objekt initialisiert wird.

Im Gegensatz zu den üblichen Methoden können Sie eine Constructor-Methode nicht direkt aufrufen. Constructor-Methoden werden von Java automatisch aufgerufen. Das funktioniert so: Wenn Sie new verwenden, um eine neue Klasseninstanz zu erstellen, führt Java drei Aufgaben aus:

Auch wenn für eine Klasse keine speziellen Constructor-Methoden definiert wurden, erhalten Sie trotzdem ein Objekt, müssen aber seine Instanzvariablen setzen oder andere Methoden aufrufen, die das Objekt zur Initialisierung braucht. Alle Beispiele, die Sie bisher geschrieben haben, verhalten sich so.

Durch Definieren von Constructor-Methoden in Ihren Klassen können Sie Anfangswerte von Instanzvariablen setzen, Methoden anhand dieser Variablen oder Methoden für andere Objekte aufrufen und die anfänglichen Eigenschaften Ihres Objekts bestimmen. Ferner können Sie Constructor-Methoden so überladen wie übliche Methoden, um ein Objekt zu erstellen, das die spezifischen Merkmale entsprechend den in new festgelegten Argumenten aufweist.

Basis-Constructors

Constructors sehen wie übliche Methoden aus, unterscheiden sich von diesen aber durch zwei Merkmale:

Listing 7.3 ist ein Beispiel mit einer einfachen Klasse namens Person und einem Constructor, der seine Instanzvariablen anhand der Argumente von new initialisiert. Ferner beinhaltet die Klasse eine Methode für das Objekt, damit es sich selbst einführen kann, und eine main()-Methode, um alle Operationen zu testen.

Listing 7.3: Die Person-Klasse

class Person {

   String name;

   int age;



   Person(String n, int a) {

      name = n;

      age = a;

   }

   void printPerson() {

      System.out.print("Hi, my name is " + name);

      System.out.println(". I am " + age + " years old.");

   }

   public static void main (String args[]) {

      Person p;



      p = new Person("Laura", 20);

      p.printPerson();

      System.out.println("- - - - - - - - - -");



      p = new Person("Tommy", 3);

      p.printPerson();

      System.out.println("- - - - - - - - - -");

   }

}

Die Ausgabe dieses Beispiels ist wie folgt:

Hi, my name is Laura. I am 20 years old.

- - - - - - - - - -

Hi, my name is Tommy. I am 3 years old.

- - - - - - - - - -

Aufrufen eines anderen Constructors

Einige Constructors, die Sie schreiben, können eventuell als übergeordnete Menge eines anderen Constructors in einer Klasse definiert sein. Das heißt, sie könnten das gleiche Verhalten mit ein paar Zusätzen aufweisen. Anstatt ein fast identisches Verhaltensmuster auf mehrere Constructor-Methoden einer Klasse zu duplizieren, ist es sinnvoller, lediglich den ersten Constructor aus dem Körper des zweiten Constructors aufzurufen. Java bietet dafür eine spezielle Syntax. Sie verwenden folgende Form, um einen Constructor, der in der aktuellen Klasse definiert ist, aufzurufen:

this(arg1, arg2, arg3...);

Die hierfür verwendeten Argumente sind selbstverständlich die Argumente des Constructors.

Constructors überladen

Wie die üblichen Methoden können auch Constructors verschiedene Zahlen und Typen von Parametern annehmen, so daß Sie Objekte mit genau den gewünschten Eigenschaften erstellen können und in der Lage sind, Eigenschaften aus verschiedenen Eingabearten zu berechnen.

Beispielsweise sind die Methoden buildRect(), die Sie heute in der MyRect-Klasse definiert haben, ausgezeichnete Constructors, weil sie die Instanzvariablen eines Objekts auf die entsprechenden Objekte initialisieren. Das bedeutet, daß Sie anstelle der ursprünglich definierten Methode buildRect() (die vier Parameter für die Eckkoordinaten heranzieht) einen Constructor erstellen können. In Listing 7.4 wird die neue Klasse MyRect2 aufgeführt, die die gleiche Funktionalität aufweist wie die ursprüngliche Klasse MyRect. Jedoch wurde sie anstelle der Methode buildRect() mit überladenen Constructor-Methoden belegt.

Listing 7.4: Die MyRect2-Klasse (mit Constructor-Methoden)

import java.awt.Point;

class MyRect2 {

   int x1 = 0;

   int y1 = 0;

   int x2 = 0;

   int y2 = 0;



   MyRect2(int x1, int y1, int x2, int y2) {

      this.x1 = x1;

      this.y1 = y1;

      this.x2 = x2;

      this.y2 = y2;

   }

   MyRect2(Point topLeft, Point bottomRight) {

      x1 = topLeft.x;

      y1 = topLeft.y;

      x2 = bottomRight.x;

      y2 = bottomRight.y;

}

   MyRect2(Point topLeft, int w, int h) {

      x1 = topLeft.x;

      y1 = topLeft.y;

      x2 = (x1 + w);

      y2 = (y1 + h);

}

   void printRect() {

      System.out.print("MyRect: <" + x1 + ", " + y1);

      System.out.println(", " + x2 + ", " + y2 + ">");

   }

   public static void main (String args[]) {

      MyRect2 rect;



      System.out.println("Calling MyRect2 with coordinates 25,25 50,50:");

      rect = new MyRect2(25, 25, 50,50);

      rect.printRect();

      System.out.println("- - - - - - - - - -");



      System.out.println("Calling buildRect w/points (10,10), (20,20):");

      rect= new MyRect2(new Point(10,10), new Point(20,20));

      rect.printRect();

      System.out.println("- - - - - - - - - -");



      System.out.print("Calling buildRect w/1 point (10,10),");

      System.out.println(" width (50) and height (50)");

      rect = new MyRect2(new Point(10,10), 50, 50);

      rect.printRect();

      System.out.println("- - - - - - - - - -");

   }

}

Nachfolgend sehen Sie die von diesem Beispielprogramm produzierte Ausgabe (sie ist mit der des vorherigen Beispiels identisch, nur der dafür nötige Code wurde geändert):

Calling buildRect with coordinates 25,25 50,50:

MyRect: <25, 25, 50, 50>

- - - - - - - - - -

Calling buildRect w/points (10,10), (20,20):

MyRect: <10, 10, 20, 20>

- - - - - - - - - -

Calling buildRect w/1 point (10,10), width (50) and height (50)

MyRect: <10, 10, 60, 60>

- - - - - - - - - -

Methoden überschreiben

Wenn Sie eine Methode in einem Objekt klassifizieren, sucht Java nach der Methodendefinition im richtigen Objekt. Falls es keine findet, wird der Methodenaufruf in der Klassenhierarchie nach oben weitergereicht, bis eine passende Methodendefinition gefunden wird. Durch die in Java implementierte Methoden-vererbung können Sie Methoden wiederholt in Subklassen definieren und verwenden, ohne den Code an sich duplizieren zu müssen.

Zuweilen soll ein Objekt aber auf die gleichen Methoden reagieren, jedoch beim Aufrufen der jeweiligen Methode ein anderes Verhalten aufweisen. In diesem Fall können Sie die Methode überschreiben. Durch dieses sogenannte Methoden-Overriding definieren Sie eine Methode in einer Subklasse, die die gleiche Unterschrift hat wie eine Methode in einer Superklasse. Dann wird zum Zeitpunkt des Aufrufs nicht die Methode in der Superklasse, sondern die in der Subklasse ermittelt und ausgeführt.

Erstellen von Methoden, die andere verbergen

Um eine Methode zu überschreiben, erstellen Sie eine Methode in der Superklasse, die die gleiche Unterschrift (Name, Ausgabeart und Parameterliste) hat wie eine Methode, die in einer Superklasse der betreffenden Klasse definiert wurde. Da Java die erste Methodendefinition ausführt, die es findet und die mit der Unterschrift übereinstimmt, wird die ursprüngliche Methodendefinition dadurch »verborgen«. Wir betrachten im folgenden ein einfaches Beispiel. Listing 7.5 zeigt eine einfache Klasse mit der Methode printMe(), die den Namen der Klasse und die Werte ihrer Instanzvariablen ausgibt.

Listing 7.5: Die PrintClass-Klasse

class PrintClass {

   int x = 0;

   int y = 1;



   void printMe() {

      System.out.println("X is " + x + ", Y is " + y);

      System.out.println("I am an instance of the class " +

      this.getClass().getName());

   }

}

Listing 7.6 umfaßt eine Klasse namens PrintSubClass, die eine Subklasse von PrintClass (extends) ist. Der einzige Unterschied zwischen PrintClass und PrintSubClass ist, daß letztere die Instanzvariable z hat.

Listing 7.6: Die PrintSubClass-Klasse

class PrintSubClass extends PrintClass {

   int z = 3;

   public static void main (String args[]) {

      PrintSubClass obj = new PrintSubClass();

      obj.printMe();

   }

}

Im folgenden die Ausgabe von PrintSubClass:

X is 0, Y is 1

I am an instance of the class PrintSubClass

In der Methode main() von PrintSubClass erstellen Sie das Objekt PrintSubClass und rufen die Methode printMe() auf. Beachten Sie, daß PrintSubClass diese Methode nicht definiert, deshalb sucht Java in allen Superklassen von PrintSubClass danach und findet sie in diesem Fall in PrintClass. Leider wird die Instanzvariable z nicht ausgegeben, weil printMe() immer noch in PrintClass definiert ist.

Wir erstellen nun eine dritte Klasse. PrintSubClass2 ist fast mit PrintSubClass identisch, jedoch wird die Methode printMe() überlagert, um die Variable z einzubinden. Listing 7.7 zeigt diese Klasse.

Listing 7.7: Die PrintSubClass2-Klasse

class PrintSubClass2 extends PrintClass {

   int z = 3;

   void printMe() {

      System.out.println("x is " + x + ", y is " + y +

         ", z is " + z);

      System.out.println("I am an instance of the class " +

         this.getClass().getName());

   }

   public static void main (String args[]) {

      PrintSubClass2 obj = new PrintSubClass2();

      obj.printMe();

   }

}

Wenn Sie diese Klasse jetzt benutzen und die Methode printMe() aufrufen, wird diesmal die Version von printMe(), die Sie für diese Klasse definiert haben, nicht diejenige, die sich in der Superklasse PrintClass befindet, aufgerufen.

Das sehen Sie an folgender Ausgabe:

x is 0, y is 1, z is 3

I am an instance of the class PrintSubClass2

Aufrufen der Originalmethode

Normalerweise gibt es zwei Gründe dafür, warum man eine Methode, die in einer Superklasse bereits implementiert ist, überschreiben will:

Den ersten Grund haben Sie bereits kennengelernt. Durch Überladen einer Methode und Schreiben einer neuen Definition für diese Methode haben Sie die ursprüngliche Definition der Methode verborgen. Zuweilen will man aber auch die ursprüngliche Definition nicht ganz ersetzen, sondern vielmehr um zusätzliche Eigenschaften erweitern. Das ist besonders nützlich, wenn Sie Eigenschaften in der Originalmethode und in derjenigen, durch die sie verborgen wird, duplizieren wollen. Sie können die Originalmethode im Körper der überschriebenen Methode aufrufen und alles einfügen, was Sie benötigen.

Um die Originalmethode innerhalb einer Methodendefinition aufzurufen, benutzen Sie das Schlüsselwort super, um den Methodenaufruf in der Hierarchie nach oben weiterzugeben:

void myMethod (String a, String b) {

   // Hier irgendwas ausführen

   super.myMethod(a, b);

   // Eventuell weiteres Zeug hier ausführen

}

Wie this ist auch das Schlüsselwort super ein Platzhalter für die Superklasse dieser Klasse. Sie können es irgendwo verwenden, wo Sie nicht auf die aktuelle Klasse, sondern die Superklasse verweisen wollen.

In Listing 7.8 sehen Sie die printMe()-Methoden aus dem vorherigen Beispiel.

Listing 7.8: Die printMe-Methoden

// aus PrintClass

void printMe() {

   System.out.println("X is " + x + ", Y is " + y);

   System.out.println("I am an instance of the class" +

      this.getClass().getName());

   }

// aus PrintSubClass2

   void printMe() {

      System.out.println("X is " + x + ", Y is " + y + ", Z is " + z);

      System.out.println("I am an instance of the class " +

         this.getClass().getName());

   }

Anstatt den Großteil des Verhaltens von der Methode der Superklasse in die Subklasse zu duplizieren, können Sie die Methode der Superklasse so umstellen, daß zusätzliche Eigenschaften mühelos hinzugefügt werden können:

// von PrintClass

void printMe() {

   System.out.println("I am an instance of the class" +

      this.getClass().getName());

   System.out.println("X is " + x);

   System.out.println("Y is " + y);

   }

Beim Überschreiben von printMe können Sie dann in der Superklasse die Originalmethode aufrufen und alles einfügen, was Sie benötigen:

// von PrintSubClass2

void printMe() {

   super.printMe();

   System.out.println("Z is " + z);

   }

Die Ausgabe des Aufrufs von printMe() in einer Instanz der Superklasse sieht so aus:

I am an instance of the class PrintSubClass2

X is 0

Y is 1

Z is 3

Constructors überschreiben

Constructor-Methoden können technisch nicht überschrieben werden. Da sie immer den gleichen Namen haben wie die aktuelle Klasse, werden keine vererbt, sondern immer neue erstellt. Das ist in den meisten Fällen sinnvoll, denn wenn ein Constructor Ihrer Klasse aufgerufen wird, wird gleichzeitig auch der Constructor mit der gleichen Unterschrift aller Superklassen aktiviert, so daß eventuell alle Teile einer Klasse initialisiert werden.

Andererseits möchten Sie eventuell beim Definieren von Constructors für eine Klasse einiges ändern, z. B. wie ein Objekt initialisiert wird. Eventuell soll es nicht durch Initialisieren der Informationen, die Ihre Klasse zusätzlich einbringt, sondern durch Änderung der bereits vorhandenen Informationen initialisiert werden. Sie erreichen das, indem Sie die Constructors Ihrer Superklasse explizit aufrufen.

Um eine übliche Methode in einer Superklasse aufzurufen, benutzen Sie super.methodname(arguments). Da Sie bei Constructors keinen Methodennamen aufrufen müssen, wenden Sie hier eine andere Form an:

super(arg1, arg2, ...);

Ebenso wie bei der Verwendung von this(...) bewirkt super(...) in Constructor-Methoden den Aufruf der Constructor-Methode für die unmittelbare Superklasse (die ihrerseits den Constructor ihrer Superklasse aufrufen kann usw.).

Das Beispiel in Listing 7.9 betrifft die Klasse NamedPoint, die sich auf die Klasse Point aus dem awt-Paket von Java erstreckt (extends). Die Point-Klasse hat nur einen Constructor, der anhand der Argumente x und y ein Point-Objekt ausgibt. NamedPoint hat eine zusätzliche Instanzvariable (eine Zeichenkette für den Namen) und definiert einen Constructor, um x, y und den Namen zu initialisieren.

Listing 7.9: Die NamedPoint-Klasse

1: import java.awt.Point;



2: class NamedPoint extends Point {

3:  String name;

4:

5:  NamedPoint(int x, int y, String name) {

6:   super(x,y);

7:    this.name = name;

8:  }

9: }

Der hier für NamedPoint (Zeilen 6 bis 8) definierte Constructor ruft die Constructor-Methode von Point auf, um die Instanzvariablen (x und y) von Point zu initialisieren. Obwohl Sie x und y ebenso gut selbst initialisieren könnten, wissen Sie eventuell nicht, ob Point noch andere Operationen ausführt, um sich zu initialisieren. Deshalb ist es immer ratsam, Constructors nach oben in der Hierarchie weiterzugeben, um sicherzustellen, daß alles richtig gesetzt wird.

Finalizer-Methoden

Finalizer-Methoden sind in gewissem Sinn das Gegenstück zu Constructor-Methoden. Während eine Constructor-Methode benutzt wird, um ein Objekt zu initialisieren, werden Finalizer-Methoden aufgerufen, kurz bevor das Objekt im Papierkorb landet und sein Speicher zurückgefordert wird.

Um eine Finalizer-Methode zu erstellen, tragen Sie eine Methode mit der folgenden Unterschrift in Ihre Klassendefinition ein:

void finalize() {

   ...

}

Im Körper dieser finalize()-Methode können Sie alle möglichen »Reinigungsprozeduren« einbinden, die das Objekt ausführen soll.

Bevor Sie mit der Verwendung von Finalizer-Methoden in Ihren Java-Programmen beginnen, sollten Sie wissen, daß diese Methoden einigen größeren Einschränkungen unterliegen. Vor allen Dingen ist nicht gewährleistet, daß eine Finalizer-Methode aufgerufen wird, bevor der Speicher des Objekts tatsächlich zurückgefordert wird, was einige Zeit dauern kann, nachdem alle Referenzen auf das Objekt entfernt wurden.

Sie können die Methode finalize() jederzeit auch selbst aufrufen. Es handelt sich um eine einfache Methode wie alle anderen. Allerdings wird durch den Aufruf von finalize() nicht veranlaßt, daß das Objekt im Papierkorb landet. Nur durch Entfernen aller Referenzen auf das Objekt wird das Objekt zum Löschen markiert, und auch dann ruft Java eventuell die finalize()-Methode nicht automatisch auf, auch wenn Sie sie aufgerufen haben.

Finalizer-Methoden eignen sich am besten zur Optimierung der Entfernung von Objekten, z. B. durch Löschen aller Referenzen auf andere Objekte, durch Reinigen aller Stellen, mit denen das Objekt in Berührung gekommen ist, oder für andere wahlweise Verhaltensweisen, die das Löschen eines Objekts vereinfachen. In den meisten Fällen benötigen Sie finalize() überhaupt nicht.

Zusammenfassung

Heute haben Sie verschiedene Techniken zum Benutzen, Wiederverwenden, Definieren und Neudefinieren von Methoden gelernt. Sie haben gelernt, wie man durch Überladen eines Methodennamens die gleiche Methode mit einem anderen Verhalten auf der Grundlage der Argumente, durch die sie aufgerufen wird, definiert. Sie haben viel über Constructor-Methoden gelernt, die benutzt werden, um ein neues Objekt beim Erstellen zu initialisieren. Sie haben mehr über Methodenvererbung erfahren und gelernt, wie Methoden in Superklassen einer Klasse durch Overriding definiert werden können. Außerdem haben Sie gelernt, daß Sie mit Finalizer-Methoden Ihr Programm »aufräumen« können.

Herzlichen Glückwunsch! Sie haben Ihre erste Woche von Java in 21 Tagen beendet. In der nächsten Woche werden Sie alles, was Sie diese Woche gelernt haben, anwenden, um Java-Applets zu schreiben und mit anspruchsvolleren Konzepten zu arbeiten. Sie werden Java-Programme zusammenstellen und mit der Java-Klassenbibliothek arbeiten.


Fragen und Antworten

F: Ich habe zwei Methoden mit folgenden Unterschriften geschrieben:

int total(int arg1, int arg2, int arg3) {   }

float total(int arg1, int arg2, int arg3) {...}

Der Java-Compiler meckert beim Kompilieren der Klasse mit diesen Methodendefinitionen. Die Unterschriften sind doch unterschiedlich. Woran liegt der Fehler?

A: Methoden-Overloading funktioniert in Java nur, wenn sich die Parameterlisten unterscheiden, entweder in der Zahl oder im Typ der Argumente. Ausgabearten sind beim Überladen von Methoden nicht relevant. Bei zwei Methoden mit genau der gleichen Parameterliste kann Java nicht wissen, welche aufzurufen ist.

F: Sie haben geschrieben, daß zum Aufrufen eines Constructors aus einem anderen Constructor die Methode this() (this(arg, arg, ...)) zu verwenden ist. Ist das die einzige Möglichkeit von this()?

A: Nein, Sie können diese Methode irgendwo einfügen, um auf den Constructor des aktuellen Objekts zu verweisen. In einem existierenden Objekt ist das Aufrufen eines Constructors eine einfache Möglichkeit, das betreffende Objekt auf seinen Standardzustand zurückzusetzen (oder es auf einen anderen Zustand abzuändern).

F: Kann ich auf Methoden, die bereits überschrieben wurden, das Overloading anwenden (d.h. kann ich Methoden erstellen, die den gleichen Namen wie eine vererbte Methode, jedoch eine andere Parameterliste haben)?

A: Sicher! So lange die Parameterliste unterschiedlich ist, spielt es keine Rolle, ob Sie einen neuen Methodennamen oder einen, den Sie aus einer Superklasse geerbt haben, definieren.

F: Ich habe eine Finalizer-Methode geschrieben, um eine Klassenvariable zu dekrementieren und eine Meldung auszugeben, wenn das Objekt im Papierkorb landet. Auf diese Weise kann ich verfolgen, wie viele Objekte dieser Klasse zu jeweils einem bestimmten Zeitpunkt laufen. Dabei wird finalize() nur manchmal aufgerufen. Wie kann ich sicherstellen, daß finalize() grundsätzlich aufgerufen wird und mein Programm korrekt läuft?

A: finalize() dient zur Bequemlichkeit, um einem Objekt Gelegenheit zu geben, hinter sich aufzuräumen. finalize() muß nicht unbedingt bei einem bestimmten Objekt aufgerufen werden, bevor es in den Papierkorb ausgelagert wird. Deshalb brauchen Sie nicht sicherzustellen, daß es immer aufgerufen wird. Wichtig ist finalize() nur, um das Programm zu optimieren.

Falls es unbedingt nötig ist, daß ein Objekt bestimmte Operationen ausführt, bevor es im Papierkorb endet, sollten Sie eine spezifische Methode, nicht finalize(), erstellen und diese Methode explizit aufrufen, bevor alle Referenzen auf das Objekt entfernt werden.


Copyright ©1996 Markt&Technik
Buch- und Software- Verlag GmbH
Alle Rechte vorbehalten. All rights reserved.

Schreiben Sie uns!

Previous Page TOC Index Next Page See Page