3.3 Referenz- und Wertetypen
In diesem Kapitel beschäftigen wir uns schwerpunktmäßig mit der Definition von Klassen. Das .NET-Typsystem kennt jedoch nicht nur Klassen zur Beschreibung von Typen. Insgesamt gibt es vier Typen, die uns .NET zur Verfügung stellt:
- Klassen (class)
- Strukturen (struct)
- Delegates (delegate)
- Enumerationen (enum)
Im weiteren Verlauf dieses und der folgenden Kapitel werden Sie natürlich noch alle kennenlernen. An dieser Stelle muss aber bereits erwähnt werden, dass sich die vier Typdefinitionen zwei Kategorien zuordnen lassen:
Zu den Wertetypen werden primitive Datentypen wie int und long sowie alle anderen auf Strukturen oder Enumerationen basierenden Typen gezählt. Zu den Referenztypen gehört beispielsweise der Typ String, alle Arrays und – ganz allgemein ausgedrückt – alle Klassen. Obwohl es im ersten Augenblick den Anschein haben mag, dass hinter Wertetypen nur »normale« Dateninformationen stehen, werden auch diese als Objekte angesehen und hinter den Kulissen der .NET-Laufzeit als solche behandelt.
3.3.1 Werte- und Referenztypen nutzen
Der Unterschied zwischen Referenz- und Wertetypen ist in der Allokierung des Systemspeichers zu finden. Eine Variable, die einen Wertetyp repräsentiert, allokiert auf dem Stack Speicher für die Daten. Der Stack ist im RAM angesiedelt, wird aber vom Prozessor durch einen sogenannten Stack Pointer direkt unterstützt. Dieser ist in der Lage, auf dem Stack neuen Speicher zu reservieren, kann ihn aber auch freigeben. Dieses Verfahren ist sehr effizient und schneller als das Allokieren von Speicher im Heap für Referenztypen. Als Heap wird der Speicher im RAM bezeichnet, der allgemeinen Zwecken zur Verfügung steht.
Wird mit
int value = 100;
eine int-Variable deklariert, wird der Wert auf dem Stack abgelegt, weil ein Integer als Struktur definiert ist. Beachten Sie bitte, dass bei einem Wertetyp wie dem Integer der new-Operator zur Initialisierung nicht angegeben werden muss. Bei einem Referenztyp ist das eine unabdingbare Forderung, denn erst mit
Circle kreis = new Circle();
wird auf dem Heap ein Speicherbereich allokiert und initialisiert, auf den danach die Referenz kreis zeigt.
Ein daraus folgendes, wichtiges Unterscheidungsmerkmal zwischen Referenz- und Wertetypen ist, dass Wertetypen niemals den Inhalt null haben können.
An dieser Stelle sei ein kurzer Hinweis erlaubt. Mit einem »Trick« kann auch ein Wertetyp den Wert null annehmen. Im Kapitel 9 werden wir darauf noch zu sprechen kommen.
Bemerkenswert ist die unterschiedliche Wirkungsweise des Zuweisungsoperators zwischen einem Werte- und einem Referenztyp. Betrachten Sie dazu zunächst die beiden folgenden Anweisungen:
long value1 = 64;
long value2 = value1;
Nach der Ausführung des Codes existieren zwei Variablen vom Typ long, die denselben Inhalt haben. Eine Variable vom Typ long wird von der Common Language Runtime (CLR) als Wertetyp erkannt und entsprechend behandelt. Die Änderung des Inhalts der Variablen value1 wird sich nicht auf den Inhalt der Variablen value2 auswirken, weil zwischen den beiden keine Verbindung existiert. Der Inhalt von value1 wird nur nach value2 kopiert.
Das ist bei Objekten, die auf Referenztypen basieren und grundsätzlich nichts anderes sind als Zeiger, ganz anders.
Circle kreis1 = new Circle();
Circle kreis2 = kreis1;
In diesem Fall haben wir zwar zwei Objektvariablen vorliegen, aber beide referenzieren denselben Speicherbereich, mit anderen Worten, dasselbe Objekt. Wird der Radius auf der Referenz kreis1 verändert, kann der neue Wert auch mit der Referenz kreis2 abgerufen werden.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.