Alle Tabs der Lerneinheit (Erklärung · Interaktiv verstehen · Praxis-Übung · Klausur-Quiz) als durchgehender Text. Ideal zum Wiederholen vor der Klausur, und für Suchmaschinen wie Google, Bing und KI-Suche (ChatGPT, Perplexity).
Erklärung
Konstruktoren + Sichtbarkeit (public / private)
Du schreibst new Student("Müller", 1001), was passiert in dieser einen Zeile? Java reserviert Speicher im Heap, ruft den Konstruktor auf, und der setzt die Felder. Aber WIE? Was passiert wenn du keinen Konstruktor definierst? Wieso darf man manche Felder nur über Methoden setzen? Genau das beantwortet dieses Topic. Klausur-Pflicht in 13/17 WInf-Prog-1-Klausuren.
Du lernst hier den Default-Konstruktor, eigene Konstruktoren mit Überladung, das Verketten über this(...) und super(...), die Reihenfolge der Feld-Initialisierung sowie die vier Sichtbarkeitsstufen (public, protected, package-private, private) und warum Encapsulation Felder vor unkontrolliertem Zugriff schützt.
Die Idee in einem Satz
Konstruktor: Spezieller Code-Block mit dem Namen der Klasse, technisch keine normale Methode (kein Rückgabetyp, nicht vererbt), der beim
newaufgerufen wird und das frisch erzeugte Objekt initialisiert. Sichtbarkeit regelt, wer von außen auf Felder/Methoden zugreifen darf.
Standard-Konstruktor (Default Constructor)
Wenn du keinen Konstruktor definierst, gibt Java dir einen kostenlos: parameterlos, leer.
public class Student {
String name;
int matrnr;
}
// kompiliert, weil Java automatisch einen Konstruktor anlegt:
// public Student() {}
Student s = new Student(); // name = null, matrnr = 0
s.name = "Müller";
s.matrnr = 1001;
Aber: sobald du selbst einen Konstruktor schreibst, ist der Default-Konstruktor weg. Klausur-Klassiker:
public class Student {
String name;
int matrnr;
public Student(String name, int matrnr) { // eigener Konstruktor
this.name = name;
this.matrnr = matrnr;
}
}
Student s = new Student(); // FEHLER, kein parameterloser Konstruktor mehr!
Eigene Konstruktoren
Konstruktor heißt genauso wie die Klasse, hat keinen Rückgabetyp (nicht mal
void).
public class Student {
String name;
int matrnr;
int semester;
public Student(String name, int matrnr) {
this.name = name;
this.matrnr = matrnr;
this.semester = 1; // Default
}
}
Das this.name = name löst den klassischen Namens-Konflikt: Parameter heißt name, Feld heißt auch name. this.name ist das Feld, name allein der Parameter. Ohne this würde name = name nur den Parameter auf sich selbst setzen, das Feld bliebe unverändert.
Konstruktor-Überladung
Mehrere Konstruktoren mit unterschiedlichen Parametern, Java wählt automatisch den passenden.
public class Student {
String name;
int matrnr;
int semester;
public Student(String name, int matrnr) {
this(name, matrnr, 1); // ruft anderen Konstruktor (Constructor Chaining)
}
public Student(String name, int matrnr, int semester) {
this.name = name;
this.matrnr = matrnr;
this.semester = semester;
}
}
Student s1 = new Student("Müller", 1001); // Semester wird 1
Student s2 = new Student("Schulz", 1002, 5); // Semester = 5
this(...) ruft einen anderen Konstruktor derselben Klasse auf. Muss die ERSTE Zeile im Konstruktor sein.
super(): der Konstruktor der Oberklasse
Bei Vererbung ruft jeder Konstruktor zuerst den Konstruktor der Oberklasse auf, explizit mit
super(...)oder implizit mitsuper().
public class Person {
String name;
public Person(String name) { this.name = name; }
}
public class Student extends Person {
int matrnr;
public Student(String name, int matrnr) {
super(name); // ruft Person(String) auf, MUSS erste Zeile sein
this.matrnr = matrnr;
}
}
Schreibst du kein super(...), fügt Java automatisch super() (parameterlos) als erste Zeile ein. Hat die Oberklasse keinen parameterlosen Konstruktor, ist das ein Compile-Error: dann musst du super(...) explizit mit Argumenten aufrufen. super(...) und this(...) schließen sich aus, pro Konstruktor nur eines, immer als erste Zeile.
Reihenfolge der Initialisierung
Bei new Student("Müller", 1001) läuft es von oben nach unten durch die Vererbungskette:
1. Heap-Speicher reservieren, alle Felder auf Default (null / 0 / false)
2. super(...): Konstruktor der Oberklasse (Person) komplett ausführen
3. Feld-Initializer der eigenen Klasse (z. B. int semester = 1;)
4. Rest des eigenen Konstruktor-Bodys (this.matrnr = matrnr;)
Merksatz: Oberklasse zuerst, dann Feld-Initializer, dann Body. Im super(...)-Aufruf darfst du noch nicht auf eigene, erst später gesetzte Felder zugreifen.
Sichtbarkeits-Modifier
Java hat 4 Sichtbarkeitsstufen (Modifier), die regeln wer von außen drauf zugreifen darf.
| Modifier | Klasse | Paket | Unterklasse | Andere |
|---|---|---|---|---|
| public | ✓ | ✓ | ✓ | ✓ |
| protected | ✓ | ✓ | ✓ | – |
| package-private (kein Keyword) | ✓ | ✓ | – | – |
| private | ✓ | – | – | – |
Eselsbrücke "PpPP": Public (alle), protected (Paket + Subklassen), package-private (nur Paket), private (nur eigene Klasse).
Feinheit bei
protected: Eine Subklasse in einem anderen Paket erreicht protected-Member überthis/superoder über eine Referenz vom Typ der Subklasse, aber nicht über eine reine Oberklassen-Instanz.protectedist damit offener als package-private, aber kein freier Zugriff von überall.
Zugriff in Aktion
Klasse Konto im Paket bank mit protected double saldo und private String pin:
// 1) Selbe Klasse (bank.Konto): alles erlaubt
this.saldo = 100; // OK
this.pin = "1234"; // OK
// 2) Andere Klasse im selben Paket (bank.Filiale)
k.saldo = 100; // OK (protected ist im Paket sichtbar)
k.pin = "1234"; // FEHLER (private)
// 3) Subklasse in anderem Paket (web.OnlineKonto extends Konto)
this.saldo = 100; // OK (geerbt, über this)
fremdesKonto.saldo; // FEHLER (protected, aber fremde Instanz)
// 4) Fremde Klasse in anderem Paket (web.Report)
k.saldo; // FEHLER (protected, außerhalb Paket + keine Subklasse)
Encapsulation, warum private?
Felder private + Getter/Setter public ist die Standard-Konvention. So kontrollierst du den Zugriff.
public class Student {
private int matrnr; // privat, kein direkter Zugriff von außen
public int getMatrnr() {
return matrnr;
}
public void setMatrnr(int neueNr) {
if (neueNr <= 0) throw new IllegalArgumentException("MatrNr muss positiv sein");
this.matrnr = neueNr; // hier kannst du Validation einbauen
}
}
Student s = new Student(...);
// s.matrnr = -1; // FEHLER, privat
s.setMatrnr(-1); // FEHLER zur Laufzeit (Exception)
Vorteile:
- Validation beim Setzen
- Read-only Felder möglich (nur Getter, kein Setter)
- Interne Änderungen möglich ohne dass externer Code bricht
- Debugging einfacher, Breakpoint im Setter sieht alle Änderungen
Visualisierung
So sieht der Ablauf von new Student(...) als Skizze aus:
new Student("Müller", 1001)
|
v
[Heap reservieren] name=null, matrnr=0, semester=0
|
v
[super(): Person(...)] name gesetzt
|
v
[Feld-Initializer] semester = 1
|
v
[Konstruktor-Body] this.matrnr = matrnr
|
v
Referenz s zeigt aufs fertige Objekt
Schalte unten durch die Schritte und achte darauf, wann die Felder initialisiert werden und ab wann sie zugreifbar sind:
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Klausur-Checkliste
- Default-Konstruktor verschwindet, sobald du selbst einen schreibst. Wenn du parameterlos auch brauchst → selbst hinzufügen.
this(...)als erste Zeile für Konstruktor-Chaining.this.feld = feldlöst Parameter-Feld-Konflikt.- private + Getter/Setter für Encapsulation. Public Felder sind Klausur-Anti-Pattern.
- Sichtbarkeits-Reihenfolge: public > protected > package > private (von offen zu eng). Merkhilfe; protected hat außerhalb des Pakets spezielle Subklassen-Regeln.
Typische Stolpersteine
1. Konstruktor mit Return-Typ. Falsch: public void Student(...). Das ist eine normale Methode mit demselben Namen wie die Klasse, aber wegen void kein Konstruktor. Konstruktor: kein Rückgabetyp, nicht mal void.
2. Default-Konstruktor erwartet. Student s = new Student(); schlägt fehl, sobald du einen anderen Konstruktor definiert hast. Java erstellt ihn nicht mehr automatisch.
3. private Felder über Vererbung. Subklassen können private Felder der Oberklasse NICHT direkt zugreifen, nur über protected/public Getter. Häufiger Klausur-Fehler.
4. this(...) an falscher Stelle. Muss erste Zeile im Konstruktor sein. Wenn du erst this.x = 1; schreibst und dann this(...), gibt's Compile-Error.
5. Package-private vergessen. Wenn du keinen Modifier schreibst (int x;), ist es package-private, nicht private. Klausur-Frage.
Klausur-Beispielaufgabe
Beispiel (typischer Klausur-Stil, zur Übung konstruiert).
Gegeben:
public class Konto {
private double saldo;
public Konto(double start) { this.saldo = start; }
}
(a) Warum schlägt new Konto() fehl? (b) Kann eine Subklasse Sparkonto im selben Paket direkt auf saldo zugreifen? (c) Wie macht man saldo für Subklassen lesbar, ohne ihn frei beschreibbar zu machen?
Lösung:
- (a) Sobald ein eigener Konstruktor (
Konto(double)) existiert, erzeugt Java keinen Default-Konstruktor mehr.new Konto()findet keinen passenden Konstruktor (no suitable constructor found). - (b) Nein,
saldoistprivate, also nur innerhalb vonKontosichtbar, für Subklassen nicht direkt. Der Paket-Aspekt ändert daran nichts. - (c) Einen
public double getSaldo()-Getter (read-only) anbieten, odersaldoaufprotectedsetzen, falls geerbte Schreibrechte gewollt sind. Für reines Lesen ist der Getter die sauberere Lösung.
Interaktiv verstehen
Code-Stepper: Schritt für Schritt
Drei Demos zum Durchklicken. Klick Step oder Auto und beobachte, wie sich Variablen und Ablauf pro Schritt ändern.
1. Konstruktor-Chaining mit this(...)
Der 2-Argument-Konstruktor delegiert an den 3-Argument-Konstruktor und setzt semester auf den Default 1.
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
2. super(): Initialisierungs-Reihenfolge
Bei Vererbung läuft super() zuerst, dann die Feld-Initializer, dann der Body. Der Body kann einen Initializer-Wert überschreiben.
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
3. Encapsulation: Validierung im Setter
private plus Setter macht ungültige Zustände unmöglich, der Setter prüft vor dem Schreiben.
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Klausur-Tipp: Bei Fehler "no suitable constructor found", du hast einen Konstruktor mit Parametern definiert und versuchst, das Objekt parameterlos zu erzeugen. Lösung: parameterlosen Konstruktor zusätzlich anlegen oder beim Aufruf Argumente liefern.
Praxis-Übung
Konstruktoren + Sichtbarkeit, Praxis-Übung
6 Aufgaben zu Default-Constructor, Overloading, Sichtbarkeitsmodifier.
Klausurfragen mit Lösungen (6)
- F1.Welche Aussage über Konstruktoren ist KORREKT?
Antwort: Konstruktoren haben keinen Rückgabetyp
Erklärung: Konstruktoren haben keinen Rückgabetyp (auch nicht void). Der Name ist identisch zur Klasse. "public void Student(...)" wäre eine normale Methode mit zufällig gleichem Namen, kein Konstruktor.
- F2.Was passiert, wenn du einen eigenen Konstruktor mit Parametern definierst?
Antwort: Der Default-Konstruktor verschwindet, parameterloses 'new' geht nicht mehr
Erklärung: Sobald du EINEN eigenen Konstruktor definierst, gibt Java den automatischen Default-Konstruktor nicht mehr aus. Wenn du parameterlos UND mit Parametern brauchst, musst du beide selbst definieren.
- F3.Welcher Sichtbarkeits-Modifier erlaubt Zugriff im selben Paket UND aus Subklassen, auch wenn diese in einem anderen Paket liegen?
Antwort: protected
Erklärung: protected: gleiche Klasse + gleiches Paket + Subklassen (auch in anderen Paketen). Public wäre überall, package-private nur im Paket (auch Subklassen in anderen Paketen nicht), private nur in der Klasse.
- F4.Eine Subklasse kann immer auf alle privaten Felder ihrer Oberklasse direkt zugreifen.
Antwort: Falsch
Erklärung: FALSCH. private bedeutet WIRKLICH nur innerhalb derselben Klasse. Subklassen müssen den Umweg über protected/public Getter/Setter nehmen. Häufiger Klausur-Stolperstein.
Typ: Wahr/Falsch
- F5.Welche Aussagen über Encapsulation (Datenkapselung) sind RICHTIG?
Richtige Antworten: Felder privat + Getter/Setter public ist Standard-Pattern; Encapsulation ermöglicht Validation beim Setzen; Encapsulation erlaubt Read-Only-Felder (nur Getter, kein Setter); Interne Implementierung kann ohne Bruch externen Codes geändert werden
Erklärung: Richtig: private+Getter/Setter Standard, Validation, Read-Only-Felder, interne Änderungen ohne externen Bruch. Falsch: Performance-Unterschied ist vernachlässigbar (JIT optimiert weg); technischer Vorteil ist real (Kontrolle).
Typ: Multi-Select
- F6.Ordne den Sichtbarkeits-Modifier dem Zugriff zu:
Zuordnungen:
- public → Überall (Klasse + Paket + Sub + Andere)
- protected → Klasse + Paket + Subklassen
- (kein Modifier) → Klasse + Paket
- private → Nur eigene Klasse
Erklärung: Standard-Sichtbarkeits-Matrix. Auswendig lernen, Klausur-Klassiker.
Typ: Zuordnung
Klausur-Quiz
Klausurfragen mit Lösungen (6)
- F1.Konstruktor-Chaining mit this(...): welche Bedingung gilt?
Antwort: this(...) muss erste Zeile sein
Erklärung: this(...) MUSS die erste ausführbare Zeile im Konstruktor sein. Genauso super(...) bei Subklassen. Wenn beides, dann super(...) zuerst, this(...) ist exklusiv (nur eine der beiden).
- F2.Was bewirkt 'this.name = name' im Konstruktor?
Antwort: Setzt das Feld auf den Parameter-Wert
Erklärung: this.name (Feld) = name (Parameter). Notwendig wenn Parameter und Feld gleichen Namen haben. Ohne this würde 'name = name' den Parameter auf sich selbst setzen, Feld bliebe unverändert.
- F3.Wenn keine Sichtbarkeit angegeben ist (z.B. 'int x;'), ist das Feld 'private'.
Antwort: Falsch
Erklärung: FALSCH. Ohne Modifier ist es 'package-private' (auch 'default' genannt). Im selben Paket zugreifbar, in anderen Paketen NICHT (auch nicht von Subklassen).
Typ: Wahr/Falsch
- F4.Sortiere die Schritte bei 'Student s = new Student("Müller", 1001)':
Richtige Reihenfolge:
- Java reserviert Speicher im Heap
- Standard-Initialisierung (alle Felder auf null/0/false)
- Konstruktor wird aufgerufen
- super(...) bzw. this(...) wird aufgerufen (falls vorhanden)
- Feld-Initializer der aktuellen Klasse laufen (z.B. int semester = 1;)
- Konstruktor-Body läuft (this.name = name, etc.)
- Referenz wird in 's' gespeichert
Erklärung: Standard-Lebenszyklus eines new-Aufrufs. Erst Speicher, dann Default-Werte, dann Konstruktor (mit super-Kette), dann die Feld-Initializer der Klasse, dann Custom-Body, am Ende Referenz.
Typ: Reihenfolge
- F5.Klasse A hat ein privates Feld 'int x'. Klasse B extends A. Wie kommt B an x?
Antwort: Über einen protected oder public Getter in A
Erklärung: Standard-Weg: A definiert einen protected/public Getter (z.B. getX()), den B aufrufen kann. Reflection geht technisch (Field.setAccessible(true)), ist aber kein Pattern. Direkter Zugriff auf private von außen (inkl. Sub) ist verboten.
- F6.Ein Konstruktor hat {{1}} Rückgabetyp und denselben {{2}} wie die Klasse. Mit {{3}} kann ein anderer Konstruktor derselben Klasse als erste Zeile aufgerufen werden. {{4}} Felder sollten meist private sein, mit öffentlichen Gettern/Settern.
Lösungen pro Lücke:
- {{1}}: keinen / kein
- {{2}}: Namen / Name
- {{3}}: this(...) / this()
- {{4}}: Encapsulation / Datenkapselung / Datenkapsel / Kapselung
Erklärung: Pflichtwissen Konstruktor + Sichtbarkeit. Diese 4 Lücken decken die häufigsten Klausur-Fragen ab. Hier akzeptieren wir Schreibvarianten (keinen/kein, Namen/Name); in der echten Klausur achte auf die exakte Formulierung laut Vorlesung.
Typ: Lückentext