Java Non-Access-Modifier
Java-Non-Access-Modifier — static, final, abstract, synchronized, transient, volatile — und was jeder davon bewirkt.
Javas Zugriffsmodifikatoren — public, protected, private — steuern, wer auf ein Member zugreifen kann. Die Non-Access-Modifier steuern, wie es sich verhält. Es handelt sich um eine überschaubare Sammlung von Schlüsselwörtern, die Eigentümerschaft, Veränderbarkeit, Threading, Serialisierung und einige weitere Aspekte beeinflussen. Dieses Kapitel gibt einen Überblick; jeder Modifier hat an anderer Stelle ein ausführlicheres Kapitel oder einen eigenen Abschnitt.
Die vollständige Liste
| Modifier | Gilt für | Was er bewirkt |
|---|---|---|
static | Felder, Methoden, verschachtelte Klassen, Blöcke | Gehört zur Klasse, nicht zu Instanzen |
final | Klassen, Methoden, Felder, Parameter, lokale Variablen | Kann nicht neu zugewiesen/überschrieben/erweitert werden |
abstract | Klassen, Methoden | Kein Rumpf / kann nicht instanziiert werden; muss von einer Unterklasse implementiert werden |
synchronized | Methoden, Blöcke | Nur ein Thread gleichzeitig darf es an einem bestimmten Lock ausführen |
volatile | Felder | Lese-/Schreibzugriffe werden nicht im thread-lokalen Speicher gecacht |
transient | Felder | Wird bei der Standard-Serialisierung übersprungen |
native | Methoden | Implementierung liegt in Nicht-Java-Code (meist C/C++) |
strictfp | Klassen, Methoden | Erzwingt strikte IEEE-754-Gleitkommaverhalten (weitgehend historisch) |
default | Interface-Methoden | Stellt einen Standard-Rumpf in einem Interface bereit |
sealed / non-sealed | Klassen, Interfaces | Schränkt ein, welche Klassen erweitern dürfen (Java 17+) |
static, final, abstract und default begegnen einem ständig. Die übrigen sieht man nur, wenn das jeweilige Problem auftritt.
static — gehört zur Klasse
Ein static-Member ist mit der Klasse selbst verknüpft, nicht mit einer einzelnen Instanz:
public class Counter {
int instanceCount; // one per Counter object
static int classCount; // one shared by everyone
}static ist so verbreitet, dass es ein eigenes Kapitel bekommt — siehe java-static.
final — kann nicht geändert werden
final bedeutet: „Diese Bindung ist nach der Zuweisung unveränderlich." Es gilt für verschiedene Dinge:
final int MAX = 100; // local variable cannot be reassigned
public final class Money {} // class cannot be extended
public final void close() {} // method cannot be overridden
private final int balance; // field assigned once, then immutablefinal ist die Grundlage von Konstanten (static final), unveränderlichen Objekten und sicherem Vererbungsdesign. Die vollständige Behandlung findet sich in java-final.
abstract — hat keinen Rumpf, muss ausgefüllt werden
abstract auf eine Klasse angewendet bedeutet: „Diese Klasse kann nicht direkt instanziiert werden — nur Unterklassen können es." Auf eine Methode angewendet bedeutet es: „Kein Rumpf hier — jede konkrete Unterklasse muss einen bereitstellen":
public abstract class Shape {
public abstract double area(); // no body
}
public class Circle extends Shape {
double r;
public double area() { return Math.PI * r * r; }
}new Shape() ist ein Kompilierfehler; new Circle() funktioniert. Behandelt in abstract classes.
synchronized — ein Thread gleichzeitig
Wenn zwei Threads dieselbe Methode am selben Objekt aufrufen könnten, stellt das Markieren der Methode mit synchronized sicher, dass nur einer gleichzeitig ausgeführt wird:
public synchronized void deposit(int amount) {
balance += amount;
}Dies ist die einfachste Form des Lockings. Im Buch gibt es später einen ganzen Abschnitt zur Nebenläufigkeit; für jetzt genügt es, das Schlüsselwort zu kennen und zu verstehen, was es grob bewirkt. Siehe synchronization für die vollständige Erklärung.
volatile — sichtbar über Threads hinweg
Ohne volatile dürfen Threads den Wert eines Feldes cachen. Lesezugriffe in einem Thread sehen unter Umständen niemals Schreibzugriffe aus einem anderen Thread:
private volatile boolean stopped = false;volatile erzwingt, dass jeder Lesezugriff aus dem Hauptspeicher erfolgt und jeder Schreibzugriff in den Hauptspeicher geht. Es ist der leichtgewichtige Verwandte von synchronized für einfache Flag-Felder — siehe volatile für die Details zum Speichermodell.
transient — bei der Serialisierung überspringen
Javas eingebaute Objektserialisierung (Serializable) schreibt standardmäßig jedes Feld. transient sagt: „Dieses hier nicht einschließen" — typischerweise verwendet für Caches, berechnete Werte oder Dinge, die außerhalb des laufenden Programms keinen Sinn ergeben:
public class Session {
String userId;
transient String passwordHash; // not serialized
}Moderner Code verwendet häufiger JSON-Serialisierer als Serializable, aber das Schlüsselwort ist in Bibliotheken, die darauf angewiesen sind, weiterhin nützlich. Mehr in serialization.
native — anderswo implementiert
native gilt für Methoden, deren Rumpf in einer anderen Sprache geschrieben ist (C/C++ über JNI). Man schreibt sie selbst selten; man sieht sie hauptsächlich in Low-Level-Bibliotheken:
public native int currentTimeMillis();strictfp — strikte Gleitkommaberechnung
Ursprünglich erzwang strictfp vorhersehbare IEEE-754-Gleitkommaarithmetik auf verschiedenen Plattformen. Ab Java 17 ist alle Gleitkomma-Mathematik implizit strikt, was das Schlüsselwort zu einem No-Op macht. Man kann es größtenteils ignorieren; es taucht in älteren Codebasen noch auf.
default — bei Interface-Methoden
Innerhalb eines Interface ermöglicht default, einen Rumpf für eine Methode bereitzustellen, anstatt sie abstrakt zu lassen:
public interface Greeter {
default String greet(String name) {
return "Hello, " + name;
}
}Ohne default hat eine Interface-Methode keinen Rumpf, und jede implementierende Klasse muss eine eigene Version schreiben. Vollständige Behandlung in default methods.
sealed und non-sealed
Eine sealed-Klasse benennt die genaue Liste der Klassen, die sie erweitern dürfen. Unterklassen müssen sich dann für final, sealed oder non-sealed entscheiden:
public sealed class Shape permits Circle, Square { }
public final class Circle extends Shape { }
public non-sealed class Square extends Shape { }Nützlich für geschlossene Typhierarchien — siehe sealed classes.
Modifier kombinieren
Modifier können in der Regel frei gestapelt werden, in dieser gebräuchlichen Reihenfolge:
public static final int MAX = 100;
private static volatile int counter;
protected abstract void onInit();Einige Kombinationen sind unzulässig: Eine Methode kann nicht gleichzeitig abstract und final, abstract und private oder abstract und static sein. Der Compiler meldet sich, wenn eine Grenze überschritten wird.
Ein ausgearbeitetes Beispiel
Was kommt als Nächstes
Die nächsten beiden Kapitel vertiefen die beiden am häufigsten verwendeten Modifier: static für Member auf Klassenebene, dann final für Unveränderlichkeit. Am besten in dieser Reihenfolge lesen.