Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage
<< | < | > | >> | API | Kapitel 8 - OOP II: Vererbung, Polymorphismus und statische Elemente

## 8.3 Statische Methoden und Membervariablen

- 8.3 Statische Methoden und Membervariablen
  - 8.3.1 Klassenvariablen
  - 8.3.2 Konstanten
  - 8.3.3 Klassenmethoden
    - Die statische Methode main
  - 8.3.4 Statische Konstruktoren

### 8.3.1 Klassenvariablen

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

Listing 8.7: Realisierung eines Instanzenzählers mit Klassenvariablen

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.

### 8.3.2 Konstanten

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 }

Listing 8.8: Verwendung von Klassenvariablen zur Definition von Konstanten

|  | Durch die Anwendung von `final` wird verhindert, daß 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. |  |
Hinweis

### 8.3.3 Klassenmethoden

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, daß 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.3.1) und Factory-Methode (siehe Abschnitt 10.3.4). |  |
Tip

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

Listing 8.9: Verwendung von Math.sqrt

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

#### Die statische Methode main

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.

### 8.3.4 Statische Konstruktoren

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 Konstruktoren 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 Konstruktors aber nicht mit jedem neu angelegten Objekt, sondern nur einmal, wenn die Klasse geladen wird.

Ein statischer Konstruktor 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 }

Listing 8.10: Definition eines statischen Konstruktors

Da der statische Konstruktor vom Laufzeitsystem aufgerufen wird, wenn die Klasse geladen wird, ist eine benutzerdefinierte Parametrisierung nicht möglich.

|  | Es ist erlaubt, mehrere statische Konstruktoren innerhalb einer Klasse zu definieren. Sie werden dann nacheinander in der textuellen Reihenfolge ihrer Deklaration ausgeführt. Wechseln sich initialisierte statische Variablen und statische Konstruktoren 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. |  |
Hinweis

Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage, Addison Wesley, Version 3.0
<< | < | > | >> | API | © 1998-2002 Guido Krüger, http://www.javabuch.de