Constructors
Kurz: Eine spezielle Methode, die beim Erzeugen eines Objekts mit new automatisch aufgerufen wird, um dessen Anfangszustand zu setzen.
Genauer: Der Konstruktor trägt immer denselben Namen wie die Klasse und hat keinen Rückgabetyp (auch nicht void). Definiert eine Klasse keinen eigenen Konstruktor, erzeugt Java automatisch einen leeren Standardkonstruktor. Konstruktoren können, wie normale Methoden, per Overloading mehrfach mit unterschiedlichen Parametern definiert werden.
class Auto {
String farbe;
Auto(String farbe) {
this.farbe = farbe;
}
}Im Detail
Sobald eine Klasse EIGENE Konstruktoren definiert, entfällt der automatisch generierte Standardkonstruktor komplett — ein häufiger Anfängerfehler ist, new Auto() (ohne Argumente) aufzurufen, obwohl nur Auto(String farbe) existiert:
class Auto {
String farbe;
int baujahr;
Auto(String farbe) {
this(farbe, 2024); // ruft den anderen Konstruktor auf - Konstruktor-Verkettung
}
Auto(String farbe, int baujahr) {
this.farbe = farbe;
this.baujahr = baujahr;
}
}
Auto a1 = new Auto("Rot"); // nutzt Baujahr 2024 als Default
Auto a2 = new Auto("Blau", 2019);this(...) als erste Zeile eines Konstruktors ruft einen anderen Konstruktor DERSELBEN Klasse auf — nützlich, um Standardwerte zu setzen, ohne Initialisierungslogik zu duplizieren. Bei Vererbung ruft ein Unterklassen-Konstruktor automatisch (oder explizit über super(...)) den Konstruktor der Oberklasse auf, bevor der eigene Code ausgeführt wird — die Objektkette wird also immer “von oben nach unten” initialisiert.
Konstruktoren bei Vererbung
class Fahrzeug {
String marke;
Fahrzeug(String marke) {
this.marke = marke;
System.out.println("Fahrzeug-Konstruktor läuft");
}
}
class Auto extends Fahrzeug {
int tueren;
Auto(String marke, int tueren) {
super(marke); // MUSS die erste Zeile sein, sonst Compiler-Fehler
this.tueren = tueren;
System.out.println("Auto-Konstruktor läuft");
}
}
new Auto("VW", 4);
// Ausgabe:
// Fahrzeug-Konstruktor läuft
// Auto-Konstruktor läuftFehlt der explizite super(...)-Aufruf, fügt der Compiler automatisch einen impliziten super() (ohne Argumente) als erste Zeile ein — das schlägt fehl, wenn die Oberklasse keinen parameterlosen Konstruktor hat, und erzwingt dann einen expliziten Aufruf mit passenden Argumenten.
Initialisierungsreihenfolge im Detail
Bevor der eigentliche Konstruktor-Code läuft, passiert in dieser Reihenfolge: (1) Feld-Initialisierer direkt bei der Deklaration (int x = 5;), (2) Instanz-Initialisierungsblöcke ({ ... } ohne Methodenname), (3) der Konstruktor-Rumpf selbst. Bei Vererbung wird dieser gesamte Ablauf zuerst komplett für die Oberklasse durchlaufen, bevor die Unterklasse an der Reihe ist.
private Konstruktoren
Ein Konstruktor muss nicht zwangsläufig public sein — ein private-Konstruktor verhindert, dass Code außerhalb der Klasse new darauf aufrufen kann. Das ist die Grundlage für das Singleton-Pattern (genau eine Instanz der Klasse existiert, erzeugt über eine eigene statische Methode statt direkt per new) und für reine Utility-Klassen mit ausschließlich statischen Methoden (wie Math), die gar nicht erst instanziiert werden sollen.
Records als moderne Alternative
Seit Java 16 gibt es record als kompakte Alternative für einfache, unveränderliche Datenklassen — Konstruktor, Getter, equals(), hashCode() und toString() werden dabei automatisch generiert, ohne dass sie ausgeschrieben werden müssen:
record Punkt(int x, int y) {}
Punkt p = new Punkt(3, 4); // Konstruktor automatisch generiert
System.out.println(p.x()); // Getter heißt wie das Feld, nicht getX()Für reine Datenhalter ohne komplexe Logik ersetzt ein record oft eine komplette klassische Klasse mit manuell geschriebenem Konstruktor und Gettern — spart deutlich Code, eignet sich aber nur, wenn die Objekte wirklich unveränderlich sein sollen.
Siehe auch: Classes, Objects, this-Keyword, Overloading, Inheritance