From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001
From: Sven Eisenhauer
+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:
+
+
+
+
+
+
+ Titel
+ Inhalt
+ Suchen
+ Index
+ DOC
+ Handbuch der Java-Programmierung, 5. Auflage
+
+ <<
+ <
+ >
+ >>
+ API
+ Kapitel 8 - OOP II: Vererbung, Polymorphismus und statische Elemente
+
+
+
+
+
+8.3 Statische Methoden und Membervariablen
+
+
+
+
+
+
+
+8.3.1 Klassenvariablen
+
+
+
+
+Listing 8.7: Realisierung eines Instanzenzählers mit Klassenvariablen
+
+
+
+
+
+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 10.4.1) +und Factory-Methode (siehe Abschnitt 10.4.4). |
+
+
|
+![]() |
+
+Das folgende Listing zeigt die Verwendung der Klassenmethode sqrt +der Klasse Math +zur Ausgabe einer Tabelle von Quadratwurzeln: + + +
+
+
+
+001 /* Listing0809.java */
+002
+003 public class Listing0809
+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 }
+
+ |
++Listing0809.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 Appletklasse
+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, 5. Auflage, Addison +Wesley, Version 5.0.1 + |
| << + | < + | > + | >> + | API + | © 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de + |