Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage |
<< | < | > | >> | API | Kapitel 9 - OOP II: Vererbung, Polymorphismus und statische Elemente |
Java ist eine konsequent objektorientierte Sprache, in der es weder globale Funktionen noch globale Variablen gibt. Da es aber mitunter sinnvoll ist, Eigenschaften zu verwenden, die nicht an Instanzen einer Klasse gebunden sind, haben die Sprachdesigner das Attribut static für Methoden und Variablen eingeführt. Eine Variable, die innerhalb einer Klasse mit dem Attribut static versehen wurde, nennt man Klassenvariable (oder auch Statische Variable). Im Gegensatz zu Instanzvariablen, die immer an ein konkretes Objekt gebunden sind, existieren Klassenvariablen unabhängig von einem Objekt.
Jede Klassenvariable wird nur einmal angelegt und kann von allen Methoden der Klasse aufgerufen werden. Da sich alle Methoden die Variable »teilen«, sind Veränderungen, die eine Instanz vornimmt, auch in allen anderen Instanzen sichtbar. Klassenvariablen sind daher vergleichbar mit globalen Variablen, denn ihre Lebensdauer erstreckt sich auf das gesamte Programm. Namenskollisionen können allerdings nicht auftreten, denn der Zugriff von außen erfolgt durch Qualifizierung mit dem Klassennamen in der Form Klassenname.Variablenname.
Ein einfaches Beispiel für die Verwendung von Klassenvariablen besteht darin, einen Instanzenzähler in eine Klasse einzubauen. Hierzu wird eine beliebige Klassenvariable eingeführt, die beim Erzeugen eines Objekts hoch- und beim Zerstören heruntergezählt wird. Das folgende Beispiel demonstriert das für die Klasse Auto:
001 /* Testauto.java */ 002 003 public class Testauto 004 { 005 static private int objcnt = 0; 006 007 public Testauto() 008 { 009 ++objcnt; 010 } 011 012 public void finalize() 013 { 014 --objcnt; 015 } 016 017 public static void main(String[] args) 018 { 019 Testauto auto1; 020 Testauto auto2 = new Testauto(); 021 System.out.println( 022 "Anzahl Testauto-Objekte: " + Testauto.objcnt 023 ); 024 } 025 } |
Testauto.java |
Die Ausgabe des Programms ist:
Anzahl Testauto-Objekte: 1
Mit auto2 wurde eine Instanz der Klasse erzeugt, auto1 ist dagegen zum Zeitpunkt der Ausgabeanweisung lediglich eine noch nicht initialisierte Objektreferenz.
Eine andere Anwendung von Klassenvariablen besteht in der Deklaration von Konstanten. Dazu wird das static-Attribut mit dem final-Attribut kombiniert, um eine unveränderliche Variable mit unbegrenzter Lebensdauer zu erzeugen:
001 public class Auto 002 { 003 private static final double STEUERSATZ = 18.9; 004 } |
Durch die Anwendung von final wird verhindert, dass der Konstanten STEUERSATZ während der Ausführung des Programms ein anderer Wert zugewiesen wird. Da Java keinen Präprozessor enthält und damit keine #define-Anweisung kennt, ist die beschriebene Methode das einzige Verfahren zur Deklaration von Konstanten in Java. Die Konvention, Konstantennamen groß zu schreiben, wurde dabei von C übernommen.
Neben Klassenvariablen gibt es in Java auch Klassenmethoden, d.h. Methoden, die unabhängig von einer bestimmten Instanz existieren. Sie werden auch als statische Methoden bezeichnet. Klassenmethoden werden ebenfalls mit Hilfe des static-Attributs deklariert und - analog zu Klassenvariablen - durch Voranstellen des Klassennamens aufgerufen.
Da Klassenmethoden unabhängig von konkreten Instanzen ihrer Klasse existieren, ist ein Zugriff auf Instanzvariablen nicht möglich. Diese Trennung äußert sich darin, dass Klassenmethoden keinen this-Zeiger besitzen. Der Zugriff auf Instanzvariablen und der Aufruf von Instanzmethoden wird daher schon zur Compile-Zeit als Fehler erkannt.
Klassenmethoden werden häufig da eingesetzt, wo Funktionalitäten zur Verfügung gestellt werden, die nicht datenzentriert arbeiten oder auf primitiven Datentypen operieren. Beispiele für beide Arten sind in der Klassenbibliothek zu finden. Zur ersten Gruppe gehören beispielsweise die Methoden der Klasse System. Die Klasse System ist eine Art Toolbox, die Funktionen wie Aufruf des Garbage Collectors oder Beenden des Programms zur Verfügung stellt. Zur zweiten Gruppe gehören beispielsweise die Methoden der Klasse Math, die eine große Anzahl an Funktionen zur Fließkomma-Arithmetik zur Verfügung stellen. Da die Fließkommatypen primitiv sind, hätte ein instanzbasiertes Methodendesign an dieser Stelle wenig Sinn.
Eine weitere Anwendung für Klassenmethoden liegt in der Instanzierung von Objekten der eigenen Klasse. Beispiele dafür finden sich in den Design-Patterns Singleton (siehe Abschnitt 11.4.1) und Factory-Methode (siehe Abschnitt 11.4.4). |
|
Das folgende Listing zeigt die Verwendung der Klassenmethode sqrt der Klasse Math zur Ausgabe einer Tabelle von Quadratwurzeln:
001 /* Listing0909.java */ 002 003 public class Listing0909 004 { 005 public static void main(String[] args) 006 { 007 double x, y; 008 for (x = 0.0; x <= 10.0; x = x + 1.0) { 009 y = Math.sqrt(x); 010 System.out.println("sqrt("+x+") = "+y); 011 } 012 } 013 } |
Listing0909.java |
Die Ausgabe des Programms ist:
sqrt(0.0) = 0.0
sqrt(1.0) = 1.0
sqrt(2.0) = 1.4142135623730951
sqrt(3.0) = 1.7320508075688772
sqrt(4.0) = 2.0
sqrt(5.0) = 2.23606797749979
sqrt(6.0) = 2.449489742783178
sqrt(7.0) = 2.6457513110645907
sqrt(8.0) = 2.8284271247461903
sqrt(9.0) = 3.0
sqrt(10.0) = 3.1622776601683795
Ein schon bekanntes Beispiel für eine Klassenmethode ist die
Methode main,
die als Startpunkt in Applikationen verwendet wird. Im Gegensatz zu
Applets, bei denen vom Laufzeitsystem eine Instanz der Applet-Klasse
erzeugt und dann durch Aufruf von Callback-Methoden bedient wird,
erfolgt der Start einer Applikation ohne die Instanzierung einer Klasse.
Der Java-Interpreter lädt lediglich das beim Starten angegebene
Klassenobjekt und sucht nach einer statischen Methode mit der Signatur:
public static void main(String[] args)
Wird diese gefunden, stellt es ein Array mit den Kommandozeilenparametern zusammen und übergibt es als Argument an main. Wird keine Methode mit dieser Signatur gefunden, gibt es einen Laufzeitfehler.
Bisher haben wir nur die Möglichkeit kennengelernt, statischen Variablen während der Deklaration einen Wert zuzuweisen. Falls komplexere Initialisierungen benötigt werden, können zur Initialisierung von statischen Variablen statische Initialisierer definiert werden.
Sie ähneln gewöhnlichen Konstruktoren und dienen wie diese dazu, Variablen mit einem definierten Startwert zu belegen. Im Gegensatz zu einem gewöhnlichen Konstruktor erfolgt der Aufruf eines statischen Initialisierers aber nicht mit jedem neu angelegten Objekt, sondern nur einmal, wenn die Klasse geladen wird.
Ein statischer Initialisierer wird als parameterlose Methode mit dem Namen static definiert:
001 class Test 002 { 003 static int i; 004 static int j; 005 006 static 007 { 008 i = 5; 009 j = 3 * i; 010 } 011 } |
Da der statische Initialisierer vom Laufzeitsystem aufgerufen wird, wenn die Klasse geladen wird, ist eine benutzerdefinierte Parametrisierung nicht möglich.
Es ist erlaubt, mehrere statische Initialisierer innerhalb einer Klasse zu definieren. Sie werden dann nacheinander in der textuellen Reihenfolge ihrer Deklaration ausgeführt. Wechseln sich initialisierte statische Variablen und statische Initialisierer im Quelltext ab, werden beide gleichwertig behandelt, d.h., die Ausführung erfolgt unabhängig vom Typ in textueller Reihenfolge. Eine Ausnahme bilden lediglich die statischen Variablen, denen Konstanten zugewiesen werden, deren Wert bereits zur Compile-Zeit feststeht. Ihre Initialisierung erfolgt - unabhängig von ihrer Position im Quellcode - unmittelbar nach dem Laden der Klasse. |
|
Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage, Addison Wesley, Version 7.0 |
<< | < | > | >> | API | © 1998, 2011 Guido Krüger & Heiko Hansen, http://www.javabuch.de |