1. Überblick über die Zugriffsmodifikatoren
In Java gibt es vier Zugriffsebenen für Klassen, Felder, Methoden und Konstruktoren:
| Modifikator | Wo ist er verfügbar? |
|---|---|
|
Überall: in der Klasse selbst, in anderen Klassen, in anderen Paketen |
|
In der Klasse, in Unterklassen (Erben), in anderen Klassen desselben Pakets |
|
Nur innerhalb des Pakets (wenn kein Modifikator explizit angegeben ist) |
|
Nur innerhalb der aktuellen Klasse |
Schauen wir uns jeden davon genauer an – mit Beispielen, ein paar Witzen und unerwarteten Wendungen.
public – öffentlicher Zugriff
public ist wie eine Ankündigung an die ganze Welt: „Allen ist der Zutritt erlaubt!“. Wenn eine Klasse, ein Feld, eine Methode oder ein Konstruktor als public deklariert ist, kann man von jeder anderen Klasse, sogar aus einem anderen Paket, darauf zugreifen.
Beispiel:
public class Cat {
public String name;
public void sayMeow() {
System.out.println("Miau!");
}
}
Auf diese Klasse und ihre Felder/Methoden kann man von überall zugreifen. Das ist praktisch, wenn Ihre Klasse für alle zugänglich sein soll – zum Beispiel wenn Sie eine Bibliothek schreiben.
Aber! Öffentliche Felder sind nicht immer eine gute Idee (siehe die vorherige Vorlesung). Üblicherweise macht man nur die Methoden public, die von außen erreichbar sein müssen, während Felder fast immer private bleiben.
private – Zugriff nur innerhalb der Klasse
private ist wie ein Tresor mit Zahlenschloss: Niemand außer der Klasse selbst hat Zugriff auf diese Member. Selbst Unterklassen (Subklassen) sehen private Felder und Methoden nicht!
Beispiel:
public class Cat {
private String secretName;
public void setSecretName(String name) {
secretName = name;
}
public String getSecretName() {
return secretName;
}
}
Hier kann secretName in anderen Klassen weder direkt gelesen noch verändert werden. Nur Cat selbst (bzw. seine Methoden) kann das. Das ist die Grundlage der Kapselung: Wir verbergen interne Details und stellen den Zugriff nur über Methoden bereit.
protected – geschützter Zugriff
protected ist wie ein VIP-Ausweis: Zugriff haben die Klasse selbst, ihre Unterklassen (auch wenn diese in anderen Paketen liegen) sowie alle Klassen innerhalb desselben Pakets.
Beispiel:
public class Animal {
protected int age;
protected void growOlder() {
age++;
}
}
Nun kann jede Klasse, die Animal erweitert, auf das Feld age und die Methode growOlder() zugreifen.
public class Cat extends Animal {
public void haveBirthday() {
growOlder();
System.out.println("Die Katze ist " + age + " Jahre alt!");
}
}
Außerdem haben alle Klassen im selben Paket Zugriff auf protected-Member.
(package-private) – Zugriff innerhalb des Pakets
Wenn Sie überhaupt keinen Zugriffsmodifikator angeben, gilt ein Klassenmitglied als package-private (oder „Standardzugriff“). Das ist wie eine Tür ohne Schloss, aber nur für die eigenen Leute: Zugriff haben nur Klassen aus demselben Paket.
Beispiel:
class Dog {
String name; // package-private
void bark() { // package-private
System.out.println("Wuff!");
}
}
Die Klasse Dog, ihr Feld name und die Methode bark() sind nur innerhalb desselben Pakets zugänglich. Ein Zugriff aus einem anderen Paket führt zu einem Kompilierfehler.
2. Einsatz der Modifikatoren bei Feldern und Methoden
Warum Felder fast immer private sind
Die Felder einer Klasse sind ihr interner Zustand. Lässt man sie öffentlich, kann beliebiger externer Code sie jederzeit verändern. Das ist, als würden Sie fremden Kindern erlauben, mit Ihren Möbeln wie mit Lego zu spielen: Eines Tages wachen Sie auf und der Kühlschrank steht kopfüber im Badezimmer.
Beispiel für schlechte Kapselung:
public class Person {
public String name;
public int age;
}
Beispiel für gute Kapselung:
public class Person {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Methoden (Getter und Setter) ermöglichen zu steuern, wie externe Klassen Felder verändern dürfen. Zum Beispiel kann man ein negatives Alter verbieten.
Wann macht man Methoden public, protected oder package-private
- public – wenn die Methode für alle zugänglich sein soll. In der Regel ist das die Hauptfunktionalität der Klasse.
- protected – wenn die Methode nur für Unterklassen oder innerhalb des Pakets benötigt wird (zum Beispiel Hilfsmethoden, die in abgeleiteten Klassen nützlich sein können).
- package-private – wenn die Methode nur innerhalb des Pakets gebraucht wird, aber von außen nicht verfügbar sein soll (zum Beispiel Implementierungsdetails).
- private – wenn die Methode nur innerhalb der Klasse selbst verwendet wird (zum Beispiel Hilfsmethoden für die interne Logik).
Beispiel:
public class BankAccount {
private double balance;
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
protected void applyInterest() {
balance *= 1.05;
}
void internalAudit() {
// package-private: nur für Klassen innerhalb des Pakets
}
private void logAction(String action) {
// nur für interne Zwecke der Klasse
}
}
3. Codebeispiele: eine Klasse mit verschiedenen Zugriffsebenen
Erstellen wir eine Klasse, die alles enthält: öffentliche, private, geschützte und paketweite Member. Außerdem versuchen wir, von anderen Klassen darauf zuzugreifen und sehen, was passiert.
package zoo;
public class Animal {
public String publicName = "Für alle zugänglich";
protected String protectedName = "Nur für Unterklassen und Paket";
String packageName = "Nur für das Paket";
private String privateName = "Nur für Animal";
public void publicMethod() {
System.out.println("Öffentliche Methode");
}
protected void protectedMethod() {
System.out.println("Geschützte Methode");
}
void packageMethod() {
System.out.println("Paket-Methode");
}
private void privateMethod() {
System.out.println("Private Methode");
}
}
Nun versuchen wir, auf diese Member aus einer anderen Klasse im selben Paket zuzugreifen:
package zoo;
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
System.out.println(animal.publicName); // OK
System.out.println(animal.protectedName); // OK
System.out.println(animal.packageName); // OK
System.out.println(animal.privateName); // Fehler: private
animal.publicMethod(); // OK
animal.protectedMethod(); // OK
animal.packageMethod(); // OK
animal.privateMethod(); // Fehler: private
}
}
Und nun versuchen wir den Zugriff aus einem anderen Paket:
package other;
import zoo.Animal;
public class Test {
public static void main(String[] args) {
Animal animal = new Animal();
System.out.println(animal.publicName); // OK
System.out.println(animal.protectedName); // Fehler: protected
System.out.println(animal.packageName); // Fehler: package-private
System.out.println(animal.privateName); // Fehler: private
animal.publicMethod(); // OK
animal.protectedMethod(); // Fehler: protected
animal.packageMethod(); // Fehler: package-private
animal.privateMethod(); // Fehler: private
}
}
Fazit:
- public – überall zugänglich.
- protected – innerhalb des Pakets und in Unterklassen zugänglich (auch aus anderen Paketen über Vererbung).
- package-private – nur innerhalb des Pakets.
- private – nur innerhalb der Klasse.
4. Best Practices: wie man den Zugriffsmodifikator wählt
Minimieren Sie die Sichtbarkeit
Je weniger Code ein Feld oder eine Methode sehen kann, desto besser. Öffnen Sie nur das, was externer Code wirklich benötigt. Das nennt man das Prinzip der geringsten Rechte.
- Felder sollten fast immer private sein. Ausnahmen gelten nur für echte Konstanten (public static final), mehr dazu in den nächsten Vorlesungen.
- Methoden macht man public nur, wenn sie Teil der externen Schnittstelle der Klasse sind.
- Hilfsmethoden (interne Logik) – private.
- Methoden für Unterklassen – protected.
- Interne Servicemethoden für das Paket – package-private.
Warum ist das wichtig?
- Jede Änderung an Implementierungsdetails kann fremden Code brechen, wenn diese Details offengelegt sind.
- Die Klasse wird schwerer zu testen und zu warten.
- Zufällige Fehler (zum Beispiel eine falsche Feldänderung) können zu Bugs führen.
Manchmal denken Einsteiger: „Wozu diese Umstände, machen wir doch einfach alles public!“ Doch wenn das Projekt wächst, muss man irgendwann die halbe Anwendung umbauen, nur weil jemand Felder der Klasse direkt verändert hat.
5. Typische Fehler beim Umgang mit Zugriffsmodifikatoren
Fehler Nr. 1: Felder public gelassen oder standardmäßig package-private.
Wenn kein Modifikator angegeben wird, ist ein Feld oder eine Methode für alle Klassen innerhalb des Pakets zugänglich. Das kann zu unerwarteten Situationen führen, wenn jemand beginnt, Ihre Felder direkt zu ändern.
Fehler Nr. 2: Versuch, auf ein private-Member aus einer anderen Klasse zuzugreifen.
Der Compiler lässt das nicht zu – es gibt einen Fehler. Wenn Sie das jedoch über Reflection (Reflexion) umgehen wollen – willkommen in einer Welt voller Bugs und unerwarteter Abstürze.
Fehler Nr. 3: Zu viel public.
Wenn man alles wahllos als public deklariert, wird die Klasse zu einer offenen Kiste voller Kabel – jeder kann am falschen Kabel ziehen und alles kaputtmachen.
Fehler Nr. 4: Sie verwenden protected nicht für Methoden, die nur für Unterklassen gedacht sind.
Wenn eine Methode nur zur Erweiterung in abgeleiteten Klassen benötigt wird, deklarieren Sie sie als protected und nicht als public.
Fehler Nr. 5: Implizite package-private-Sichtbarkeit.
Man vergisst manchmal, den Modifikator anzugeben, und die Methode wird für das gesamte Paket zugänglich. Das kann überraschen, wenn man dachte, sie sei private.
GO TO FULL VERSION