Eine Anleitung zu Konstruktoren in Java

1. Einleitung

Konstruktoren sind die Torhüter des objektorientierten Designs .

In diesem Tutorial werden wir sehen, wie sie als ein einzelner Speicherort fungieren, von dem aus der interne Status des zu erstellenden Objekts initialisiert wird.

Lassen Sie uns fortfahren und ein einfaches Objekt erstellen, das ein Bankkonto darstellt.

2. Einrichten eines Bankkontos

Stellen Sie sich vor, wir müssen eine Klasse erstellen, die ein Bankkonto darstellt. Es enthält einen Namen, ein Erstellungsdatum und ein Gleichgewicht.

Lassen Sie uns auch die toString- Methode überschreiben , um die Details auf der Konsole zu drucken:

class BankAccount { String name; LocalDateTime opened; double balance; @Override public String toString() { return String.format("%s, %s, %f", this.name, this.opened.toString(), this.balance); } } 

Diese Klasse enthält jetzt alle erforderlichen Felder zum Speichern von Informationen zu einem Bankkonto, enthält jedoch noch keinen Konstruktor.

Dies bedeutet, dass beim Erstellen eines neuen Objekts die Feldwerte nicht initialisiert werden:

BankAccount account = new BankAccount(); account.toString(); 

Die Lauf toString Methode wird in einer Ausnahme führen oben , weil die Objekte Name und geöffnet sind nach wie vor null :

java.lang.NullPointerException at com.baeldung.constructors.BankAccount.toString(BankAccount.java:12) at com.baeldung.constructors.ConstructorUnitTest .givenNoExplicitContructor_whenUsed_thenFails(ConstructorUnitTest.java:23) 

3. Ein Konstruktor ohne Argumente

Lassen Sie uns das mit einem Konstruktor beheben:

class BankAccount { public BankAccount() { this.name = ""; this.opened = LocalDateTime.now(); this.balance = 0.0d; } } 

Beachten Sie einige Dinge über den Konstruktor, den wir gerade geschrieben haben. Erstens ist es eine Methode, aber es gibt keinen Rückgabetyp. Dies liegt daran, dass ein Konstruktor implizit den Typ des von ihm erstellten Objekts zurückgibt. Der Aufruf neuen Bankaccount () jetzt rufen Sie den Konstruktor oben.

Zweitens braucht es keine Argumente. Diese spezielle Art von Konstruktor wird als Konstruktor mit o-Argumenten bezeichnet .

Warum brauchten wir es aber nicht zum ersten Mal? Wenn wir keinen Konstruktor explizit schreiben, fügt der Compiler einen Standardkonstruktor ohne Argumente hinzu .

Aus diesem Grund konnten wir das Objekt zum ersten Mal erstellen, obwohl wir keinen expliziten Konstruktor geschrieben haben. Der Standardkonstruktor ohne Argumente setzt einfach alle Mitglieder auf ihre Standardwerte.

Für Objekte ist das null, was zu der Ausnahme führte, die wir zuvor gesehen haben.

4. Ein parametrisierter Konstruktor

Ein wirklicher Vorteil von Konstruktoren besteht darin, dass sie uns helfen, die Kapselung beim Injizieren des Zustands in das Objekt aufrechtzuerhalten .

Um mit diesem Bankkonto etwas wirklich Nützliches zu tun, müssen wir in der Lage sein, tatsächlich einige Anfangswerte in das Objekt einzufügen.

Dazu schreiben wir einen parametrisierten Konstruktor , dh einen Konstruktor, der einige Argumente akzeptiert :

class BankAccount { public BankAccount() { ... } public BankAccount(String name, LocalDateTime opened, double balance) { this.name = name; this.opened = opened; this.balance = balance; } } 

Jetzt können wir mit unserer BankAccount- Klasse etwas Nützliches tun :

 LocalDateTime opened = LocalDateTime.of(2018, Month.JUNE, 29, 06, 30, 00); BankAccount account = new BankAccount("Tom", opened, 1000.0f); account.toString(); 

Beachten Sie, dass unsere Klasse jetzt 2 Konstruktoren hat. Ein expliziter Konstruktor ohne Argumente und ein parametrisierter Konstruktor.

Wir können so viele Konstruktoren erstellen, wie wir möchten, aber wir möchten wahrscheinlich nicht zu viele erstellen. Das wäre etwas verwirrend.

Wenn wir zu viele Konstruktoren in unserem Code finden, können einige Creational Design Patterns hilfreich sein.

5. Ein Kopierkonstruktor

Konstruktoren müssen nicht nur auf die Initialisierung beschränkt sein. Sie können auch zum Erstellen von Verhaltensweisen verwendet werden. Stellen Sie sich vor, wir müssen in der Lage sein, aus einem vorhandenen Konto ein neues Konto zu erstellen.

Das neue Konto sollte den gleichen Namen wie das alte Konto, das heutige Erstellungsdatum und kein Guthaben haben. Wir können das mit einem Kopierkonstruktor machen :

public BankAccount(BankAccount other) { this.name = other.name; this.opened = LocalDateTime.now(); this.balance = 0.0f; } 

Jetzt haben wir folgendes Verhalten:

LocalDateTime opened = LocalDateTime.of(2018, Month.JUNE, 29, 06, 30, 00); BankAccount account = new BankAccount("Tim", opened, 1000.0f); BankAccount newAccount = new BankAccount(account); assertThat(account.getName()).isEqualTo(newAccount.getName()); assertThat(account.getOpened()).isNotEqualTo(newAccount.getOpened()); assertThat(newAccount.getBalance()).isEqualTo(0.0f); 

6. Ein verketteter Konstruktor

Natürlich können wir möglicherweise einige der Konstruktorparameter ableiten oder einige von ihnen als Standardwerte angeben.

Zum Beispiel könnten wir einfach ein neues Bankkonto mit nur dem Namen erstellen.

Erstellen wir also einen Konstruktor mit einem Namensparameter und geben Sie den anderen Parametern Standardwerte:

public BankAccount(String name, LocalDateTime opened, double balance) { this.name = name; this.opened = opened; this.balance = balance; } public BankAccount(String name) { this(name, LocalDateTime.now(), 0.0f); }

Mit dem Schlüsselwort this rufen wir den anderen Konstruktor auf.

Wir müssen bedenken , dass , wenn wir eine Oberklassenkonstruktors zu Kette wollen wir verwenden müssen Super statt diese .

Denken Sie auch daran, dass dieser oder Super- Ausdruck immer die erste Aussage sein sollte.

7. Werttypen

Eine interessante Verwendung von Konstruktoren in Java ist die Erstellung von Wertobjekten . Ein Wertobjekt ist ein Objekt, das seinen internen Status nach der Initialisierung nicht ändert.

Das heißt, das Objekt ist unveränderlich . Die Unveränderlichkeit in Java ist etwas nuanciert und beim Herstellen von Objekten ist Vorsicht geboten.

Lassen Sie uns fortfahren und eine unveränderliche Klasse erstellen:

class Transaction { final BankAccount bankAccount; final LocalDateTime date; final double amount; public Transaction(BankAccount account, LocalDateTime date, double amount) { this.bankAccount = account; this.date = date; this.amount = amount; } } 

Beachten Sie, dass wir jetzt das endgültige Schlüsselwort verwenden, wenn wir die Mitglieder der Klasse definieren. Dies bedeutet, dass jedes dieser Mitglieder nur innerhalb des Konstruktors der Klasse initialisiert werden kann. Sie können später in keiner anderen Methode neu zugewiesen werden. Wir können diese Werte lesen, aber nicht ändern.

Wenn wir mehrere Konstruktoren für die Transaction- Klasse erstellen , muss jeder Konstruktor jede endgültige Variable initialisieren. Wenn Sie dies nicht tun, wird ein Kompilierungsfehler angezeigt.

8. Fazit

Wir haben eine Tour durch die verschiedenen Arten gemacht, wie Konstruktoren Objekte erstellen. Konstrukte bilden bei vernünftiger Verwendung die Grundbausteine ​​des objektorientierten Entwurfs in Java.

Codebeispiele finden Sie wie immer auf GitHub.