04.03.06 Sichtbarkeitsmodifizierer
In Java ist es möglich über Sichtbarkeitsmodifizierer die Sichtbarkeit von Klassen, Attributen und Methoden zu erweitern bzw. einzuschränken. Damit hat man die Kontrolle darüber, wie auf diese Bestandteile von Außerhalb zugegriffen werden kann.
Sichtbarkeitsmodifizierer
Sichtbarkeitsmodifizierer dienen dem OOP-Konzept des Information Hiding, dem Verbergen von Implementationsdetails. So werden Sichtbarkeiten und direkte Zugriffe auf Elemente einer Klasse, wie Variablen und Methoden eingeschränkt, bzw. verhindert.
In Java gibt es vier Sichtbarkeiten
- Öffentlich
- Geschützt
- Paketsichtbar
- Privat
Bis auf die Paketsichtbarkeit gibt es zu jeder Stufe ein entsprechendes Schlüsselwort.
Dies ist public
für Öffentlich, protected
für geschützt und private
für privat. Fehlt die Angabe eines solchen Schlüsselwortes wird standardmäßig die Paketsichtbarkeit angenommen.
Es gelten dabei folgende Mechanismen.
- Auf öffentliche Elemente kann von jeder anderen Klasse aus zugegriffen werden.
- Auf geschützte Elemente kann nur von Klassen aus zugegriffen werden, welche sich im gleichen Paket befinden oder welche eine Kindklasse einer solchen Klasse sind.
- Auf paketsichtbare Elemente kann nur von Klassen aus zugriffen werden, welche sich im gleichen Paket befinden.
- Auf private Elemente kann nur die zugehörige Klasse selbst zugreifen, für alle anderen sind diese nicht zugänglich.
In unseren Beispielen zu Attributen und Methoden haben wir bereits solche Modifizierer verwendet. Um dies aber nun zu festigen, erstellen wir ein paar neue Beispiele, welche sich explizit mit den Sichtbarkeiten befassen.
Public
Auf mit public
versehene Elemente kann – wie bereits erwähnt – jeder zugreifen.
public class PublicTest { public int i; public void ausgabe() { System.out.println(i); } }
In unserer Klasse PublicTest
gibt es ein öffentliches Attribut i
und eine öffentliche Methode ausgabe
.
Auf beide Elemente kann von Außerhalb zugegriffen werden, wie wir in unserer Klasse Test
sehen können.
public class Test { public static void main(String[] args) { PublicTest pt = new PublicTest(); pt.i = 20; pt.ausgabe(); } }
Wir erzeugen zu Beginn ein Objekt pt
von unserer Klasse PublicTest
. Dann greifen wir auf das Attribut i
dieses Objektes zu und weisen diesem den Wert „20“ zu. Im Anschluss verwenden wir die öffentliche Methode ausgabe
.
Es ist aber oft von Vorteil nicht allen Elementen einer Klasse die volle Sichtbarkeit zu geben.
- Man muss zusätzliche Abhängigkeiten überprüfen, bevor der Wert eines Attributes geändert werden kann. (z.B. Wertebereiche)
- Es gibt Methoden, welche nur von anderen Methoden des gleichen Objektes aufgerufen werden sollten, da eine alleinige Verwendung keinen Sinn macht.
- Der Entwickler muss nicht immer zwangsläufig die komplette Struktur einer Klasse wissen, um damit arbeiten zu können.
- In der OOP gilt es, Elementen soviel Sichtbarkeit wie nötig und sowenig Sichtbarkeit wie möglich zu geben, um ungewollte Abhängigkeiten und Seiteneffekte zu vermeiden.
Hierzu ein weiteres Beispiel.
public class Bier { public String name; public double stammwuerze; public void setzeName(String aNeuerName) { this.name = aNeuerName; } public void setzeStammwuerze(double aNeueStammwuerze) { if ((aNeueStammwuerze < 0) || (aNeueStammwuerze > 30)) { System.out.println("Ungültige Stammwürze!"); } else { this.stammwuerze = aNeueStammwuerze; } } public void ausgabe() { System.out.println(this.name + " hat " + this.stammwuerze + "% Stammwürze."); } }
Die Klasse Bier hat die zwei öffentlichen Attribute name
und stammwuerze
. Für diese beiden Attribute gibt es jeweils eine Methode, welche den Wert verändern kann – setzeName
und setzeStammwuerze
. Als dritte Methode gibt es noch ausgabe
, welche die Attribute auf der Konsole ausgibt.
Wichtig bei dieser Klasse ist die Methode setzeStammwuerze
, welche erst nach einer Gültigkeitsüberprüfung des Parameters aNeueStammwuerze
den Stammwürzegehalt unseres Bieres setzt. Wir verwenden die Klasse Bier
wieder in einem Testprogramm.
public class Test { public static void main(String[] args) { Bier andechs = new Bier(); Bier becks = new Bier(); andechs.setzeName("Andechs Doppelbock"); andechs.setzeStammwuerze(18.5); becks.setzeName("Becks Pilsner"); becks.stammwuerze = 45; andechs.ausgabe(); becks.ausgabe(); } }
Hier werden zwei Biersorten andechs
und becks
erzeugt. Das Objekt andechs
bekommt einen passenden Namen und der Stammwürzegehalt wird mit der zugehörigen Methode setzeStammwuerze
gesetzt. Anders verhält es sich bei unserem Objekt becks
. Hier setzen wir zunächst ebenfalls den entsprechenden Namen. Die Zuweisung des Wertes für die Stammwürze wird aber nicht über die Methode setzeStammwuerze
, sondern über den direkten Zugriff auf das Objektattribut stammwuerze
vollzogen. Somit greift unsere Gültigkeitsüberprüfung nicht und wir erhalten für die Stammwürze einen ungültigen Wert.
Für diese Beispiel wird aus Übersichtsgründen nicht direkt nach Biersorten unterschieden, sondern nur für alle Biere die Stammwürze überprüft. Den aktuell höchsten Stammwürzegehalt hat Samichlaus-Bier mit 28,72% Stammwürze. Deshalb der Vergleich mit 30 als Obergrenze für alle Biere. Der erfahrene Bierkenner allerdings weiß, dass Biere nach Pilsner Brauart, wie unser Becks Pilsner, jedoch nur maximal 12,5% Stammwürzegehalt erreichen.
Als Ausgabe erhalten wir.
Andechs Doppelbock hat 18.5% Stammwürze.
Becks Pilsner hat 45.0% Stammwürze.
Natürlich hätten wir auch für becks
die Methode setzeStammwuerze
verwenden können. Man muss aber davon ausgehen, dass sobald Elemente nach Außen hin sichtbar sind, werden diese auch von irgendjemand direkt verwendet. Um so etwas gleich von vorn herein auszuschließen, sollte die Sichtbarkeit der Attribute geändert werden.
Private
In unserem vorangegangenen Beispiel war die Zuweisung ungültiger Werte möglich. Dies wollen wir nun unter Verwendung des Modifizierers private
unterbinden.
Dazu ändern wir einfach nur die Sichtbarkeit der Attribute name
und stammwuerze
unserer Klasse Bier
. Aus public
machen wir nun private
.
public class Bier { private String name; private double stammwuerze; [...] }
Die Klasse Test
lässt sich nun nicht mehr kompilieren, da diese versucht direkt auf ein nicht sichtbares Attribut zuzugreifen.
becks.stammwuerze = 45;
Wir erhalten die Fehlermeldung.
The field Bier.stammwuerze is not visible.
Wir werden nun also gezwungen den Wert der Stammwürze auf andere Weise zu setzen. Da die Klasse Bier
hierzu die öffentliche Methode setzeStammwuerze
bereit stellt, weichen wir auf diese aus. So haben wir es ja auch schon für Andechs Doppelbock gemacht.
becks.setzeStammwuerze(45);
Führen wir das Testprogramm aus erhalten wir folgende Ausgabe.
Ungültige Stammwürze!
Andechs Doppelbock hat 18.5% Stammwürze.
Becks Pilsner hat 0.0% Stammwürze.
Bei dem Setzen der Stammwürze für Becks bekommen wir die Meldung, dass dies ein ungültiger Wert ist. In der Konsequenz wird somit die Stammwürze für Becks nicht geändert und bei der darauf folgenden Ausgabe erhalten wir eine Stammwürze von 0.0%.
Sie sehen also wie wichtig es sein kann die Sichtbarkeit von Attributen und Methoden nur auf die maximal Notwendige zu beschränken, um Überraschungen vorzubeugen.
Paketsichtbar und Protected
Zwischen den beiden Extremen public
und private
gibt es noch die geschützte und die Paket Sichtbarkeit.
Auf Elemente einer Klasse, welche die Standardsichtbarkeit (Paket) verwenden, kann nur innerhalb desselben Paketes zugegriffen werden.
Der Modifizierer protected
verhält sich ähnlich, nur wird hierdurch noch erlaubt, dass erbende Klassen ebenfalls Zugriff auf diese geschützten Elemente haben, auch wenn sie nicht im gleichen Paket liegen.