EMZETT.
Login

Encapsulation

Kurz: Felder einer Klasse private halten und den Zugriff nur über öffentliche Methoden (Getter/Setter) erlauben — schützt den internen Zustand vor unkontrollierter Veränderung von außen.

Genauer: Ein Setter kann zusätzlich validieren, bevor er einen Wert übernimmt (z. B. negative Werte ablehnen) — das wäre bei einem direkt öffentlichen Feld nicht möglich. Encapsulation ist einer der vier Grundpfeiler der OOP und macht eine Klasse robuster gegen Fehlbenutzung durch anderen Code.

class Konto {
    private double saldo;
    public double getSaldo() { return saldo; }
    public void einzahlen(double betrag) {
        if (betrag > 0) saldo += betrag;
    }
}

Im Detail

Grundmuster: privates Feld, öffentliche Zugriffsmethoden

class Person {
    private int alter; // von außen NICHT direkt zugreifbar
 
    public int getAlter() {
        return alter;
    }
 
    public void setAlter(int alter) {
        if (alter < 0 || alter > 150) {
            throw new IllegalArgumentException("Ungültiges Alter: " + alter);
        }
        this.alter = alter;
    }
}
 
Person p = new Person();
p.setAlter(30);       // ok
// p.alter = -5;      // würde NICHT kompilieren - Feld ist private
p.setAlter(-5);       // kompiliert, wirft aber zur Laufzeit IllegalArgumentException

Ohne Kapselung (öffentliches Feld int alter;) könnte jeder Code irgendwo im Programm das Feld auf einen ungültigen Wert setzen, ohne dass die Klasse das verhindern kann — der Fehler taucht dann oft erst viel später und an ganz anderer Stelle auf, wenn mit dem inzwischen kaputten Zustand weitergearbeitet wird, was das Debuggen erschwert. Mit Kapselung läuft JEDE Änderung zwingend durch den Setter, der die Validierung erzwingt — ändert sich später die Validierungslogik (z. B. Höchstalter auf 130 senken), muss das nur an EINER Stelle angepasst werden, nicht überall im aufrufenden Code.

Praxisbeispiel: geschützter Kontostand

class Konto {
    private double saldo;
 
    public Konto(double startguthaben) {
        if (startguthaben < 0) {
            throw new IllegalArgumentException("Startguthaben darf nicht negativ sein");
        }
        this.saldo = startguthaben;
    }
 
    public double getSaldo() {
        return saldo;
    }
 
    public void einzahlen(double betrag) {
        if (betrag <= 0) throw new IllegalArgumentException("Betrag muss positiv sein");
        saldo += betrag;
    }
 
    public void abheben(double betrag) {
        if (betrag <= 0) throw new IllegalArgumentException("Betrag muss positiv sein");
        if (betrag > saldo) throw new IllegalStateException("Nicht genug Guthaben");
        saldo -= betrag;
    }
}

Hier zeigt sich der eigentliche Wert von Kapselung: abheben() garantiert, dass der Saldo niemals negativ wird, egal von wo im Programm die Methode aufgerufen wird. Ein öffentliches Feld double saldo könnte dagegen jederzeit von außen auf einen beliebigen (auch negativen) Wert gesetzt werden, ohne dass die Klasse das verhindern könnte — die Invariante “Saldo ist nie negativ” ließe sich gar nicht garantieren.

Getter/Setter sind keine Pflicht — und keine Garantie

Ein verbreitetes Missverständnis ist, Kapselung bedeute automatisch “für jedes Feld einen Getter UND Setter schreiben”. Tatsächlich ist ein Feld ohne Setter (nur Getter) oft die bessere Wahl, wenn es sich nach der Konstruktion gar nicht mehr ändern soll — das erzwingt Unveränderlichkeit (Immutability) und macht die Klasse automatisch thread-sicher gegenüber gleichzeitigen Lesezugriffen. Umgekehrt ist ein Getter, der einfach nur return feld; macht, ohne jede zusätzliche Logik, manchmal auch ein Zeichen dafür, dass das Feld eigentlich gar nicht gekapselt werden müsste (z. B. bei reinen Datenhaltern). Viele IDEs generieren Getter/Setter automatisch per Rechtsklick (“Generate…”), moderne Java-Versionen (ab Java 16) bieten mit record außerdem eine kompakte Variante für unveränderliche Datenklassen, bei denen alle Felder automatisch private final sind und nur Getter (ohne Setter, ohne get-Präfix) generiert werden — record Person(int alter) {} erzeugt implizit eine Methode alter() statt getAlter().

Abgrenzung zu den anderen OOP-Grundpfeilern

Encapsulation wird oft mit Abstraction verwechselt, weil beide Begriffe irgendwie mit “Verstecken” zu tun haben — der Unterschied: Abstraction versteckt Komplexität (WIE etwas intern funktioniert), Encapsulation versteckt und schützt Zustand (WELCHE Daten direkt zugreifbar sind). Ein interface ist primär ein Abstraction-Werkzeug, während private-Felder mit Gettern/Settern primär Encapsulation sind — beide Prinzipien werden in der Praxis aber meist gemeinsam eingesetzt.

Siehe auch: Modifiers, OOP, Classes, Abstraction, Constructors