04.07 Weitere Modifizierer
Sie kennen bereits die Sichtbarkeitsmodifizierer und wissen, wie Sie mit static umgehen müssen. In Java existieren aber noch weitere Modifizierer – abstract, final, native, strictfp, synchronized, transient
und volatile
– deren Verwendung Sie in diesem Kapitel (mit Ausnahme von abstract
, welches in einem eigenen Kapitel behandelt wird) kennen lernen.
final
Das Schlüsselwort final
wird verwendet, um Code-Elemente als unveränderbar zu markieren. final
ist aber nicht gleich final
. Das Verhalten von final
unterscheidet sich durch das Element, welches als final
deklariert wird.
- Primitive Datentypen …
final int i = 23;
… dürfen nicht verändert werden. Folgendes ist also unzulässig
i = 42;
und endet in einem Compiler-Fehler.
- Objekte …
final StringBuffer buff = new StringBuffer();
… dürfen manipuliert (Aufruf von Methoden, verändern von Attributen, …) aber nicht neu angelegt werden. Folgendes ist also zulässig
buff.append("Manipulation");
Wohingegen dieses
buff = new StringBuffer("Neu Anlegen");
ebenfalls in einem Compiler-Fehler endet.
- Klassen …
public final class FinalClass {}
… die diesen Modifizierer zugewiesen bekommen, dürfen nicht beerbt werden. Folgendes ist also unzulässig
public class SubFinalClass extends FinalClass {}
und endet selbstverständlich wieder in einem Compiler-Fehler.
- Methoden …
public class FinalTest { public final void finalMethod() {} }
… dürfen nicht überschrieben werden. Auch dieser Code
public class SubFinalTest extends FinalTest { public void finalMethod() {} }
endet folglich in einem Compiler-Fehler.
final
wird für die unterschiedlichsten Möglichkeiten eingesetzt. Diese wären u. a.:
- Um Überschreiben oder Verändern von Attributen, Klassen und Methoden zu verhindern
- Um Performance zu gewinnen, da der Compiler dadurch in der Regel auf die dynamische Methodensuche verzichten kann
- Um lokale Variablen in lokalen Klassen sichtbar zu machen (siehe 04.10 Innere Klassen)
- Um Konstanten einer Klasse/eines Objekts in der Form
public (static) final int SOMETHING = 1;
zu definieren
Wenn Sie einem finalen Attribut bei der Initialisierung noch keinen Wert zuweisen, so müssen Sie dies spätestens im Konstruktor, oder im (statischen) Initialisierer erledigen.
public class AClass { private final int xyz; public AClass(int value) { this.xyz = value; } }
native
Dieser Modifizierer wird ausschließlich für Methoden verwendet. Methoden, die als native
deklariert wurden, haben keinen Methoden-Körper sondern bestehen nur aus der Methoden-Signatur, einem Rückgabetyp und einem Sichtbarkeitsmodifizierer. Deshalb werden sie auch mit einem Semikolon abgeschlossen.
public native double calcSomethingNative(double val1, double val2);
Hinter jeder als native
deklarierten Methode steckt eine nativ, also Betriebssystem abhängig, ausgelagerter Funktion in einer entsprechenden Programm-Bibliothek (z. B. .dll bei Windows), welche aufgerufen wird. Ist dies nicht der Fall, kommt es natürlich zu einem Fehler. Sie lernen im JNI Kapitel mehr über native Methoden.
strictfp
Dieses Schlüsselwort für Klassen und Methoden erzwingt, dass alle Operationen mit Fließkommazahlen innerhalb ihres Gültigkeitsblock nach der einfachen Darstellung laut IEEE 754 verarbeitet werden, welche besagt, dass alle Zahlen mit einfacher Genauigkeit (float
) 32 Bit, und alle mit doppelter Genauigkeit (double
) 64 Bit groß sind. Diese Vorgehensweise wurde bis Java 1.1 standardmäßig angewandt. Seit Java 1.2 wird mit der erweiterten Darstellung (sofern von der Hardware/vom System unterstützt) nach IEEE 754 gearbeitet, welche min. 43 bzw. 79 Bit für die selben Datentypen reserviert. Um diese Gegebenheit zu umgehen wurde strictfp
eingeführt.
public strictfp class StrictFPClass {} public strictfp double calcStrictFp(double d1, double d2) { return d1 * d2; }
Die erweiterte Darstellung bietet bei Systemen, die selbige unterstützen, folgende Vorteile:
- Größere Genauigkeit bei Rechenoperatoren
- Höhere Performance, da nicht zwischen einfacher und erweiterter Darstellung konvertiert werden muss
Durch die größere Genauigkeit der erweiterten Darstellung kann es allerdings dazu kommen, dass die selben Rechenoperatoren auf unterschiedlichen Systemen unterschiedliche Ergebnisse liefern.
Für Sie als Programmierer hat ein float
aber weiterhin immer 32 Bit und ein double
immer 64 Bit. Die erweiterte Darstellung kommt lediglich intern zur Laufzeit des Programms während Rechenoperatoren zur Geltung.
synchronized
Unterschiedliche Threads können eine Methode parallel aufrufen. Um dies zu verhindern, muss diese Methode mit dem Schlüsselwort synchronized
versehen werden. Führen Sie zur Veranschaulichung folgenden Code aus:
public class SyncTest { public static void main(String[] args) { new Thread(new Runnable() { public void run() { printSynchronized("Thread 1"); } }).start(); new Thread(new Runnable() { public void run() { printSynchronized("Thread 2"); } }).start(); new Thread(new Runnable() { public void run() { printNormal("Thread 3"); } }).start(); new Thread(new Runnable() { public void run() { printNormal("Thread 4"); } }).start(); } public static synchronized void printSynchronized(String print) { System.out.println("Print synchronized Start: " + print); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Print synchronized End: " + print); } public static void printNormal(String print) { System.out.println("Print normal Start: " + print); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Print normal End: " + print); } }
Es ist nicht weiter schlimm, wenn Sie obigen Code nicht verstehen. Er soll Ihnen nur die Verwendung von synchronized
demonstrieren. Weitere Informationen zu Threads finden Sie später im entsprechenden Kapitel.
transient
Variablen, die als transient
deklariert wurden, werden beim Speichern eines Objekts nicht mit gespeichert. Wird das Objekt also wieder geladen, erhält sie den zugewiesenen Standardwert. Hierzu lernen Sie mehr im Kapitel über ObjectStreams.
transient int i = 23;
volatile
Auch dieses Schlüsselwort steht wieder im Zusammenhang mit Threads. Threads können eigene Kopien von Variablen halten, wodurch es passieren kann, dass unterschiedliche Threads mit unterschiedlichen (veralteten) Variablenwerten arbeiten. Mit volatile
zwingen Sie die Virtual Machine dazu, vor jedem Zugriff auf diese Variable den Wert zu synchronisieren.
volatile int volI = 42;
Das hier scheint mir logisch nicht ganz schlüssig (beidesmal IEEE 754):
„Dieses Schlüsselwort für Klassen und Methoden erzwingt, dass alle Operationen mit Fließkommazahlen innerhalb ihres Gültigkeitsblock nach der einfachen Darstellung laut IEEE 754 verarbeitet werden, welche besagt, dass alle Zahlen mit einfacher Genauigkeit (float) 32 Bit, und alle mit doppelter Genauigkeit (double) 64 Bit groß sind. Diese Vorgehensweise wurde bis Java 1.1 standardmäßig angewandt. Seit Java 1.2 wird mit der erweiterten Darstellung (sofern von der Hardware/vom System unterstützt) nach IEEE 754 gearbeitet, welche min. 43 bzw. 79 Bit für die selben Datentypen reserviert. „
Hallo spinatwachtel,
bitte nennen Sie Ihre Quelle und das zitierte Schlüsselwort.
Danke und Grüße
Stefan
strictfp und der Abschnitt dazu.
War das jetzt verständlich? Ganz so viel Text ist auf dieser Seite ja nicht und den Abschnitt habe ich auch noch zitiert…
OK, war mir nicht klar, dass Sie sich auf den schon etwas älteren Artikel beziehen. Was finden sie „logisch nicht ganz schlüssig“?
Grüße
Stefan
Das hier:
„.. IEEE 754 verarbeitet werden, welche besagt, dass alle Zahlen mit einfacher Genauigkeit (float) 32 Bit..“
im Vergleich zu:
„..Seit Java 1.2 wird mit der erweiterten Darstellung (sofern von der Hardware/vom System unterstützt) nach IEEE 754 gearbeitet, welche min. 43 bzw. 79 Bit für ..“
Hat sich die IEEE 754 hier geändert, oder ist es bei einem Teil einfach eine andere Nummer?
Hallo spinatwachtel,
in der Tat, das ist etwas unglücklich formuliert. Wenn man sich den Wikipedia-Artikel ansieht, wird es etwas deutlicher:
http://de.wikipedia.org/wiki/Ieee754#Zahlenformate_und_andere_Festlegungen_des_IEEE-754-Standards
Es wird zwischen „extended“ (min 43 bzw. 79 Bit) und „normal“ (32 bzw. 64 Bit) unterschieden.
Ich hoffe das Hilft?!
Grüße
Stefan
Hallo,
aha. So ergibt das auch mehr Sinn.
Danke!