Logo Wissenstransfer Gerhard at CichnaDotCom

>> Wissensdatenbank / Objektorientiertes Programmieren

Konstruktoren zur Erzeugung von Objekten

Der Standard-Konstruktor

Wie der Name schon verspricht, erfüllt der new-Operator den Zweck, ein neues Objekt zu einer gegebenen Klasse zu erzeugen. Um zu wissen, mit welchen Werten die Attribute eines Objektes belegt werden und wie man diese Definition beeinflussen kann, wird der Standard-Konstruktor eingesetzt. Er wird durch den new-Operator aufgerufen und gibt das erzeugte Objekt als Ergebnis zurück.

Man kann sich den Standard-Konstruktor wie eine spezielle Art einer Methode vorstellen, die es nur einmal pro Klasse geben darf. Abgesehen von ein paar Einschränkungen ist die Syntax einer normalen Methode sehr ähnlich.
Definition und Aufruf des Standard-Konstruktors

Für die Definition des Standard-Konstruktors gelten die folgenden Regeln: Der Name des Konstruktors muss immer mit der Klasse übereinstimmen. Er besitzt keinen Rückgabetyp und die Sichtbarkeit sollte immer public sein, damit andere Klassen ein Objekt dieser Klasse per new-Operator erzeugen können. Im Gegensatz zu den überladenen Konstruktoren hat der Standard-Konstruktor keine Parameter.
Daher erfüllt der Standard-Konstruktor im Regelfall nur zwei Aufgaben:

  1. Anpassen der Defaultwerte für primitive Datentypen
  2. Erzeugung von nicht-primitiven Attributen (Objekte)

Wenn die beiden oben genannten Aufgaben für eine bestimmte Klasse nicht notwendig sein sollten, so ist auch die Definition eines Standard-Konstruktors nicht erforderlich und man kann sie weglassen. In einem solchen Fall wird implizit ein leerer Standard-Konstruktor vom Java-Compiler hinzugefügt. Das heißt, der Konstruktor ist zwar nicht im Quelltext sichtbar, kann aber trotzdem mit dem new-Operator aufgerufen werden und somit ein Objekt erzeugen.

Bei der Verwendung von Konstruktoren im Allgemeinen ist zu beachten, dass nicht mehr benötigte Objekte automatisch von der Java-Laufzeitumgebung gelöscht werden. Man spricht in diesem Zusammenhang von "Garbage Collection" oder automatischer Speicherverwaltung. Das heißt, es ist im Gegensatz zu anderen Programmiersprachen wie C/C++ oder Objective C normalerweise nicht nötig, die Objekte durch eine Programmanweisung explizit zu zerstören. Selbst bei Programmen mit hohem Speicherbedarf funktioniert die in Java integrierte automatische Speicherverwaltung sehr gut. Sollte es trotzdem Bedarf zur Freigabe von Speicher geben, kann der Garbage Collector durch die Anweisung System.gc() aufgerufen werden.

Überladen von Konstruktoren

In der Praxis ist es üblich, Objekte unmittelbar nach ihrer Erzeugung mit Werten zu belegen. Mit den bislang bekannten Mitteln würde dies mit einer Methode umgesetzt, die ein Objekt erzeugt, die Attribute mit den Werte, welche als Parameter übergeben wurden, setzt und das Objekt zurückgibt.

Für solche Fälle kann der Standard-Konstruktor überladen werden. Das heißt, man definiert einen zweiten Konstruktor zusätzlich zum Standard-Konstruktor. Dieser Konstruktor besitzt im Gegensatz zum Standard-Konstruktor eine Parameterliste. Mit der Parameterliste kann nun genau festgelegt werden, mit welchen Attributen das Objekt zur Laufzeit mit Informationen gefüllt werden soll.
Beispiel eines überladenen Standard-Konstruktors

Ein weiteres Problem tritt auf, wenn Objekte einer Klasse je nach Ausgangssituation mit unterschiedlichen Kombinationen von Attributen initialisiert werden sollen. In solchen Fällen ist es notwendig, einen passenden Konstruktor für jede Kombination an bereitstehenden Informationen zu definieren. Dank des Überladens ist es in Java möglich, beliebig viele Konstruktoren zu programmieren, sofern sich die Parameterlisten unterscheiden. Dabei ist es durchaus sinnvoll, die Konstruktoren sich gegenseitig aufrufen zu lassen, um doppelten Code zu vermeiden und die Wartbarkeit zu erhöhen. Das Aufrufen von anderen Konstruktoren innerhalb überladener Konstruktoren geschieht mit der Anweisung this(). Diese Anweisung muss immer an erster Stelle stehen, andernfalls produziert der Compiler eine Fehlermeldung.
Definition mehrerer überladener Konstruktoren

Die Abarbeitungsreihenfolge beim Aufruf einer solchen Verkettung von überladenen Konstruktoren ist wie folgt:
Falls ein Programm den zweiten überladenen Konstruktor aufruft, um ein neues Objekt mit allen Attributen zu erzeugen, so wird zunächst der erste überladene Konstruktor aufgerufen. Ihm werden die erforderlichen Parameter übergeben. Der erste Konstruktor ruft wiederum zunächst den Standard-Konstruktor auf, natürlich ohne Parameter. Ist der Anweisungsblock des Standard-Konstruktors abgearbeitet, wird mit dem Anweisungsblock des ersten überladenen Konstruktors fortgesetzt usw.

Konstruktoren eignen sich auch zur Erstellung von Kopien gleichartiger Objekte. Dafür kann man einen "Copy-Konstruktor" verwenden, der dann wie folgt aufgerufen wird:
Kunde neuesKundenObjekt = new Kunde(bestehendesKundenObjekt);

Copy-Konstruktor, der eine Kopie eines Kunden-Objekts erzeugen kann:
Copy-Konstruktor

In diesem Zusammenhang ist auch die Zuweisung warenkorb = original.warenkorb; nochmals zu überdenken, denn sie führt dazu, dass anschließend beide Kundenobjekte (das Original und der Klon) denselben Warenkorb besitzen, da ihre jeweils in warenkorb gespeicherten Referenzen anschließend auf dasselbe Warenkorbobjekt verweisen. In einem solchen Fall spricht man dann auch von einer flachen Kopie, denn nur das Objekt selbst, nicht aber auch die von ihm referenzierten Objekte werden geklont.

Würde man hingegen in dem Copy-Konstruktor bei der Zuweisung von warenkorb wiederum einen entsprechenden Copy-Konstruktor zur Klasse Warenkorb aufrufen, dann hätte man einen geklonten Kunden mit einem ebenfalls geklonten Warenkorb:
warenkorb = new Warenkorb(original.warenkorb);

In diesem Fall spricht man dann von einer tiefen Kopie, da auch Referenzdatentypen durch das Anlegen neuer Objekte geklont und nicht einfach nur die Referenz kopiert werden.

Konstruktoren und Vererbung

Sofern Klassen in einer Vererbungshierarchie stehen, kann es in bestimmten Fällen notwendig sein, auf den Konstruktor der Oberklasse zuzugreifen. In der Programmiersprache Java ist es möglich, den Konstruktor der Oberklasse aufzurufen. Hierzu wird das Schlüsselwort super verwendet. Genauso wie das Schlüsselwort this kann auch super mit oder ohne Parameter aufgerufen werden. Im ersten Fall wird nach einem geeigneten überladenen Konstruktor gesucht, im letzteren Fall wird der Standard-Konstruktor der Oberklasse aufgerufen.
Aufruf Konstruktor Oberklasse mit super()