Jedes Nicht-Array nicht-String-Objekt auf dem Heap gespeichert enthält einen 8- oder 16-Byte-Header (Größen für 32/64-Bit-Systeme), gefolgt von den Inhalten des Objekt des öffentlichen und private Felder. Arrays und Strings haben den obigen Header und einige weitere Bytes, die die Länge des Arrays und die Größe jedes Elements (und möglicherweise die Anzahl der Dimensionen, die Länge jeder zusätzlichen Dimension usw.) definieren, gefolgt von allen Feldern des ersten Element, dann alle Felder der Sekunde, usw. Gegeben eine Referenz auf ein Objekt, kann das System den Header leicht untersuchen und bestimmen, um welchen Typ es sich handelt.
Referenzspeicherorte enthalten einen 4- oder 8-Byte-Wert, der ein auf dem Heap gespeichertes Objekt eindeutig identifiziert. In aktuellen Implementierungen ist dieser Wert ein Zeiger, aber es ist einfacher (und semantisch äquivalent), ihn als eine "Objekt-ID" zu betrachten.
Speicherorte vom Typ "Wert" enthalten den Inhalt der Felder des Wertetyps, haben jedoch keinen zugeordneten Header. Wenn Code eine Variable vom Typ Int32
deklariert, müssen Sie keine Informationen mit dieser Int32
speichern, die besagt, was es ist. Die Tatsache, dass dieser Speicherort eine Int32
enthält, wird effektiv als Teil des Programms gespeichert und muss daher nicht am Speicherort selbst gespeichert werden. Dies stellt eine große Ersparnis dar, wenn z. B. eine Million Objekte aufweist, von denen jede ein Feld vom Typ Int32
aufweist. Jedes der Objekte, die das Int32
enthalten, hat einen Header, der die Klasse identifiziert, die es bedienen kann. Da eine Kopie dieses Klassencodes mit jeder der Millionen Instanzen arbeiten kann, ist die Tatsache, dass das Feld ein Teil des Codes ist, viel effizienter, als wenn der Speicher für jedes dieser Felder Informationen darüber enthält, worum es sich handelt .
Boxing ist erforderlich, wenn eine Anforderung zum Übergeben des Inhalts eines Werttypspeicherorts an einen Code gestellt wird, der diesen bestimmten Wertetyp nicht erwartet. Code, der Objekte unbekannten Typs erwartet, kann einen Verweis auf ein Objekt akzeptieren, das auf dem Heap gespeichert ist. Da jedes auf dem Heap gespeicherte Objekt über einen Header verfügt, der angibt, um welchen Objekttyp es sich handelt, kann Code diesen Header immer dann verwenden, wenn ein Objekt so verwendet werden muss, dass sein Typ bekannt sein muss.
Beachten Sie, dass es in. NET möglich ist, sogenannte generische Klassen und Methoden zu deklarieren. Jede solche Deklaration erzeugt automatisch eine Familie von Klassen oder Methoden, die identisch sind mit Ausnahme des Objekttyps, von dem sie zu handeln erwarten. Wenn man eine Int32
an eine Routine DoSomething<T>(T param)
übergibt, wird automatisch eine Version der Routine erzeugt, in der jede Instanz des Typs T
effektiv durch Int32
ersetzt wird. Diese Version der Routine weiß, dass jeder als Typ T
deklarierte Speicherort einen Int32
enthält. Genau wie in dem Fall, in dem eine Routine für die Verwendung eines Int32
Speicherorts fest codiert war, ist es nicht erforderlich, Typinformationen mit diesen zu speichern Orte selbst.
Kommend von C++ nach Java, war ich völlig vollständig extrem schockiert, als ich diese Tatsache entdeckte ... – GuLearn