Zum Inhalt
wannacode

Kapselung

Kurz gesagt: Kapselung bedeutet, dass eine Klasse ihre Daten mit private versteckt und sie nur über ihre eigenen Methoden zeigt, über Getter und Setter, die die Werte prüfen.

Problem

Minus 500 €

In der letzten Lektion haben wir die Prüfung beim Abheben in eine Methode gesteckt. Das Feld ist aber offen, und jeder kann direkt hineinschreiben:

Account account = new Account("Maria", 100);
account.withdraw(500);
account.balance = -500;
System.out.println(account.balance);
Ausgabe
-500.0

Die Methode hat das Abheben von 500 € richtig abgelehnt. Die nächste Zeile hat den Kontostand einfach von Hand gesetzt. Die Prüfung ist da, aber man kann sie umgehen. Wir brauchen eine Möglichkeit zu sagen: „Nur das Konto fasst den Kontostand an.“

Die Idee

private: nur die Klasse fasst es an

Schreib private vor das Feld statt public:

class Account {
private String owner;
private double balance;
// ...
}

Jetzt kommt nur noch der Code in der Klasse Account an das Feld. Von außen lässt sich die Zeile

account.balance = -500;

nicht mehr kompilieren:

Fehler beim Kompilieren
error: balance has private access in Account

private und public heißen Zugriffsmodifizierer. Sie sagen, wer ein Feld, eine Methode oder einen Konstruktor sehen darf. Die Klasse versteckt ihre Daten und zeigt sie nur über ihre eigenen Methoden. Das nennt man Kapselung.

Genauer, für Neugierige
  • Ohne Modifizierer ist ein Feld oder eine Methode im selben Paket sichtbar (einer Gruppe von Klassen in einem Ordner). Solange alles in einer Datei steht, ist das fast wie public. Schreib den Modifizierer deshalb ausdrücklich hin.
  • Es gibt auch protected: sichtbar in der Klasse und in ihren Unterklassen. Du triffst es im Modul „Vererbung und Polymorphie“.
  • public class Main ist eine öffentliche Klasse. Eine Datei kann nur eine davon haben, und sie heißt wie die Datei. Deshalb haben unsere Klassen darüber kein public.

Die Idee

Lesen, ohne anzufassen

Von außen können wir den Kontostand jetzt nicht einmal lesen. Deshalb gibt die Klasse eine Methode, die ihn nur zurückgibt:

Main.java
class Account {
private String owner;
private double balance;
public Account(String owner, double balance) {
this.owner = owner;
this.balance = balance;
}
public String getOwner() {
return owner;
}
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public boolean withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true;
}
return false;
}
}
public class Main {
public static void main(String[] args) {
Account account = new Account("Maria", 100);
account.withdraw(30);
account.deposit(50);
System.out.println(account.getOwner() + ": " + account.getBalance() + " €");
}
}
Ausgabe
Maria: 120.0 €

getBalance() ist ein Getter: eine Methode, die den Wert eines Feldes zurückgibt. Ihr Name ist get plus der Name des Feldes mit großem Anfangsbuchstaben. Der Kontostand ändert sich nur über deposit und withdraw, und die prüfen.

withdraw gibt jetzt boolean zurück: ob das Abheben geklappt hat. So weiß jeder, der abhebt, ob es funktioniert hat.

Account account = new Account("Maria", 100);
account.withdraw(500);
account.deposit(50);
System.out.println(account.getBalance());
Schritt für Schritt, in Worten
  1. balance ist private: Das Glas bedeutet, dass von außen kein Weg zum Feld führt.
  2. Das Abheben geht durch die Prüfung in der Methode: 500 ist mehr als 100. Abgelehnt, und der Kontostand bleibt, wie er ist.
  3. Auch die Einzahlung wird geprüft: 50 ist ein positiver Betrag. Die Methode addiert ihn.
  4. getBalance() gibt eine Kopie des Kontostands heraus. Das Feld selbst bleibt versteckt.

Probier es aus

Abgelehnt

Was gibt das Programm aus?

Account account = new Account("Maria", 100);
System.out.println(account.withdraw(150));
account.deposit(-20);
System.out.println(account.getBalance());
Antwort

Die Idee

Setter: eine Änderung mit Prüfung

Manchmal muss Code von außen ein Feld ändern, aber nicht auf jeden beliebigen Wert. Das Alter eines Tieres kann sich ändern, aber es kann nicht negativ sein:

class Animal {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0) {
this.age = age;
}
}
}
Animal cat = new Animal();
cat.setAge(4);
cat.setAge(-3);
System.out.println(cat.getAge());
Ausgabe
4

setAge ist ein Setter: eine Methode, die einen Wert in einem Feld speichert, nachdem sie ihn geprüft hat. Bei -3 schlägt die Prüfung fehl, und das Alter bleibt 4.

Die Idee

Welches Feld bekommt einen Setter?

Nicht jedes Feld braucht einen Setter, und manche brauchen nicht einmal einen Getter. Überleg, was Code von außen mit dem Produkt tun können soll:

  • Name und Preis werden beim Erzeugen des Produkts gesetzt und danach nur gelesen: nur ein Getter;
  • die Stückzahl im Warenkorb ändert sich, ist aber mindestens 1: ein Getter und ein Setter mit Prüfung.
class Product {
private String name;
private double price;
private int quantity;
public Product(String name, double price) {
this.name = name;
this.price = price;
this.quantity = 1;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
if (quantity >= 1) {
this.quantity = quantity;
}
}
}
Product coffee = new Product("Kaffee", 7.50);
coffee.setQuantity(3);
coffee.setQuantity(0);
System.out.println(coffee.getName() + " x" + coffee.getQuantity());
Ausgabe
Kaffee x3

Die Regel lautet: Fang mit private für alles an und öffne nur, was du brauchst. Ein Setter, der ohne Prüfung alles speichert, bringt das Problem aus der ersten Karte zurück.

In Java schreibst du Getter und Setter von Hand. IntelliJ IDEA kann sie erzeugen: Alt+Insert → Getter and Setter.

Probier es aus

Was fehlt?

Der Kontostand soll nur in der Klasse sichtbar sein. Was steht in der Lücke?
class Account {
     double balance;
}

Probier es aus

Finde den Fehler

Das Feld ist private, und trotzdem wird der Kontostand -500:

Account account = new Account();
account.setBalance(100);
account.withdraw(30);
account.setBalance(-500);
System.out.println(account.getBalance());
Ausgabe
-500.0

Welche Zeile in der Klasse bricht den Schutz?

Wähle die Zeile mit dem Fehler.

Übung

Versteckte Daten

Löse die Aufgaben in deinem Editor. Alle Felder sind private.

1. Person. Person mit Name und Alter, ein Konstruktor, die Getter getName() und getAge() und introduce().

Ausgabe
Maria ist 34 Jahre alt.
Hallo, ich bin Maria und bin 34 Jahre alt.

2. Ein Konto ohne Minus. Account mit Inhaber und Kontostand. Eine Einzahlung nimmt nur einen positiven Betrag an. Eine Abhebung gibt zurück, ob sie geklappt hat, und lässt den Kontostand nie unter 0 fallen. Code von außen kann den Kontostand lesen, aber nicht schreiben.

Main
Account account = new Account("Peter", 50);
account.deposit(25);
account.deposit(-10);
System.out.println(account.withdraw(100));
System.out.println(account.withdraw(40));
System.out.println("Kontostand: " + account.getBalance() + " €");
Ausgabe
false
true
Kontostand: 35.0 €

3. Tier. Animal mit Art und Alter. Die Art wird im Konstruktor gesetzt und danach nur gelesen. Das Alter hat einen Setter, der eine negative Zahl ablehnt und eine Meldung ausgibt. Auch der Konstruktor geht durch dieselbe Prüfung.

Main
Animal cat = new Animal("Katze", 3);
cat.setAge(4);
cat.setAge(-1);
System.out.println(cat.getSpecies() + ", " + cat.getAge() + " Jahre");
Ausgabe
Ungültiges Alter: -1
Katze, 4 Jahre

Weitere Aufgaben

  • Note. Eine Klasse Grade mit dem Namen eines Fachs und einer Note von 2 bis 6. Der Setter lehnt alles außerhalb dieser Grenzen ab. Probier es mit 5, 7 und 1.
  • Produkt mit Rabatt. Gib dem Product aus der Lektion eine Methode, die einen Rabatt in Prozent anwendet und nur 1 bis 90% annimmt. Der Preis hat keinen Setter.

Test

Teste dich

1. Das Feld balance ist private. Von wo aus kann es geändert werden?
2. Warum hat das Konto keinen Setter für den Kontostand?
3. Der Code ruft setAge(-3) auf, und setAge prüft age >= 0. Was passiert mit dem Alter?
4. Was bedeutet Kapselung?

Erstellt von Ivo Gergov im Rahmen der Kampagne von Evo Tech für zugängliche Programmierausbildung ·