Advanced Services | Statische Daten und Methoden |
In unseren bisherigen Beispielen war der Datenteil eine Klasse immer objektbezogen. Jedes Objekt, das mit Hilfe eines Konstruktors angelegt wird, enthält dann diesen Datenteil als seine Eigenschaften. Manchmal sind jedoch auch Daten nützlich, die nicht objektbezogen sind, sondern klassenbezogen, also Daten, die nur ein einziges Mal pro Klasse angelegt werden. Solche Daten nennen wir in Zukunft statische Daten. Jedes Objekt der Klasse darf auf sie zugreifen, aber sie gehören zu keinem Objekt, sie gehören eben zur Klasse. Die Deklaration von statischen Daten sieht folgendermaßen aus:
public class StaticDemo { // statischer Datenteil private static int counter ; // nichtstatischer Datenteil private String vor, nach ; // Konstruktoren // ... // Methoden // ... }
Und so kann man sich das im Speicher vorstellen:
Es gibt verschiedene Begriffe, um diesen Unterschied klarzumachen. Statt Datenteil einer Klasse spricht
man auch von Membervariablen und unterscheidet dann zwischen Instanzvariablen und Klassenvariablen. Die
folgende Graphik macht also zweimal dieselbe Untercheidung mit anderen Begriffen.
Nichtstatische Daten werden pro Objekt durch einen Konstruktor initialisiert. Es liegt nahe, etwas ähnliches für statische Daten zu erwarten. Tatsächlich gibt es einen statischen Konstruktor Wie ein Konstruktor liegt er auf der obersten Ebene der Klasse, wird jedoch durch das Schlüsselwort static eingeleitet:
Im folgende Beispiel haben wir unser Beispiel um einen statischen Konstruktor ergänzt. Wie dem Kommentar zu entnehmen ist, sind Accessmodifier hier nicht erlaubt. Ein statischer Konstruktor ist also immer public. Die statische Variable count dient dazu, die Anzahl der angelegten Instanzen zu zählen.
public class Person
{
// Membervariablen
private static int itemCount;
private String vorname;
private String nachnname;
// statischer Konstruktor
//Zugriffsmodifizierer bei statischen Konstruktoren nicht zulässig
static Person()
{
count = 0;
Console.WriteLine("static constructor");
}
// Konstruktoren
public Person() : this("", "")
{
Console.WriteLine("default constructor");
}
public Person(String n) : this("", n)
{
Console.WriteLine("constructor Person(String n)");
}
public Person(String v, String n)
{
Console.WriteLine("constructor Person(String v, String n)");
count++;
this.vorname = v;
this.nachnname = n;
}
public int GetItemCount()
{
return itemCount;
}
public static int ItemCount
{
get { return itemCount; }
}
//...
}
Wenn Sie zu der obigen Klasse ein Demoprogramm schreiben können Sie feststellen, in welcher Reihenfolge die
Konstruktoren bei der Initialisierung abgearbeitet werden.
Der statische Konstruktor wird einmal vor dem Anlegen des ersten Objekts aufgerufen. Danach nie mehr. Es gibt aber noch eine zweite Situation, in der die statischen Daten angelegt werden, ohne daß überhaupt ein Objekt existiert.
Jetzt, wo wir statische Daten kennengelernt haben, erscheinen die statischen Methoden in einem klareren Licht. Statische Methoden arbeiten mit statischen Daten zusammen. Statische Methoden haben Zugriff auf statische Daten, aber keinen Zugriff auf nichtstatische Daten, da diese objektbezogen sind. Daraus ergibt sich aber auch, daß statische Daten beim ersten Aufruf einer statischen Methode initialisiert sein müssen, also muß der statische Konstruktor vor dem Aufruf abgearbeitet sein. Bestätigen Sie das mit einem passenden Demoprogramm.
Ein Standardbeispiel für einen statischen Datenteil ist ein Zähler, der die Anzahl der Objekte einer Klasse zählt. Wir werden das als Übung erledigen.
Auch Properties gibt es auf statischer Ebene. Die Syntax ist die gleiche wie für nichtstatische Properties. Man ergänzt lediglich das Wort static. Das folgende Beispiel legt legt eine Get-Property an. Das sich anschließende Main verwendet die Property um die interne Variable auszulesen.
public class Person { // Membervariablen private static int itemCount; private String vorname; private String nachnname; // statischer Konstruktor //Zugriffsmodifizierer bei statischen Konstruktoren nicht zulässig static Person() { itemCount = 0; Console.WriteLine("static constructor"); } // Konstruktoren public Person() : this("", "") { Console.WriteLine("default constructor"); } public Person(String n) : this("", n) { Console.WriteLine("constructor Person(String n)"); } public Person(String v, String n) { Console.WriteLine("constructor Person(String v, String n)"); itemCount++; this.vorname = v; this.nachnname = n; } public static int ItemCount { get { return itemCount; } } //... }
class Test { static void Main(string[] args) { Person p = new Person("a", "w"); Person p2 = new Person("y", "x"); Console.WriteLine(Person.ItemCount); } }
Ein Counter für die Klasse Person
Reihenfolge der Initialisierung bei Vererbung