Warum haben manche Sprachen benötigen, Boxing und Unboxing?
Dies ist nicht eine Frage, was ist boxing und unboxing
es ist eher warum tun Sprachen wie Java und C#, dass ?
Ich bin sehr vertraut mit C++, STL und Boost.
In C++, ich könnte etwas schreiben, wie diese sehr leicht,
std::vector<double> dummy;
Ich habe einige Erfahrung mit Java, aber ich war wirklich überrascht, denn ich hatte etwas zu schreiben wie diese,
ArrayList<Double> dummy = new ArrayList<Double>();
Meine Frage, warum sollte es ein Objekt sein, was ist so schwer technisch zu zählen primitive Typen beim sprechen über Generika ?
- Kommt von C++ zu Java, ich war komplett voll extrem schockiert, als ich entdeckte diese Tatsache...
Du musst angemeldet sein, um einen Kommentar abzugeben.
In Java der Fall ist, ist es aufgrund der Art und Weise Generika Arbeit. In Java generics sind eine compile-Zeit-trick, der verhindert, dass Sie aus putting eine
Image
- Objekt in einArrayList<String>
. Jedoch, Java generics implementiert, mit type-erasure: der generische Typ-Informationen verloren gehen, während der Laufzeit. Dies war aus Gründen der Kompatibilität, da Generika Hinzugefügt wurden relativ spät in Java ist das Leben. Dies bedeutet, dass zur Laufzeit eineArrayList<String>
ist effektiv einArrayList<Object>
(oder besser: nurArrayList
erwartet und zurückObject
alle seine Methoden), CASTET automatisch zuString
wenn Sie einen Wert Abfragen.Aber da
int
nicht ableiten ausObject
können Sie es nicht in einer ArrayList, die erwartet wird (zur Laufzeit)Object
und Sie können nicht werfen einObject
zuint
entweder. Dies bedeutet, dass die primitiveint
muss gewickelt werden, in einer Art, die nicht Erben ausObject
wieInteger
.C# beispielsweise funktioniert anders. Generics in C# sind auch erzwungen, die zur Laufzeit und keine Boxen erforderlich ist
List<int>
. Boxen nur in C# passiert, wenn Sie versuchen, speichern Sie einen Wert-Typ wieint
in einen reference-type variable wieobject
. Daint
in C# erbt vonObject
in C# schreibenobject obj = 2
ist durchaus gültig, aber die int wird geschachtelt werden, das geschieht automatisch durch den compiler (keineInteger
Referenz-Typ ist für den Benutzer verfügbar gemacht oder nichts).Boxing und unboxing sind eine Notwendigkeit, geboren aus dem Weg, dass Sprachen (wie C# und Java) implementieren Sie Ihre memory-allocation-Strategien.
Bestimmten Typen zugeordnet sind, auf dem stack und auf dem heap. Um die Behandlung einer stack-allokierten Typ als heap-allocated Typ, Boxen ist erforderlich, um die stack-allokierten Typ auf dem heap. Unboxing ist die umgekehrte Prozesse.
In C# - stack-allokierten Arten genannt werden Wert-Typen (z.B.
System.Int32
undSystem.DateTime
) und heap-allocated Arten genannt werden Referenz-Typen (z.B.System.Stream
undSystem.String
).In einigen Fällen ist es vorteilhaft, in der Lage sein zu behandeln, einen Wert geben wie ein Referenz-Typ (Reflexion ist ein Beispiel), aber in den meisten Fällen, boxing und unboxing sind am besten vermieden werden.
Ich glaube, das ist auch, weil primitive Erben nicht von Object. Angenommen, Sie haben eine Methode, die will in der Lage sein, alles zu akzeptieren, da die parameter, wie zB.
Müssen Sie möglicherweise an eine einfache Grundwert der Methode, wie:
Würden Sie in der Lage zu tun, ohne dass boxing/unboxing, denn 5 ist eine primitive und nicht ein Objekt. Sie könnten zu einer überlastung der print-Methode für jeden primitiven Typ, um eine solche Funktionalität, aber es ist ein Schmerz.
Ich kann Ihnen nur sagen, für Java, weshalb es keine Unterstützung für primitve Typen im Bereich der Generika.
Zuerst gab es das problem, dass die Frage, diese zu unterstützen, jedes mal brachte Sie auf die Diskussion, wenn java sollte sogar primitive Typen. Was natürlich behindert die Diskussion von der eigentlichen Frage.
Zweite der wichtigste Grund, nicht auch war, dass Sie wollten binäre Abwärtskompatibilität, so würde es laufen unverändert auf eine VM nicht bewusst, Generika. Diese rückwärts-Kompatibilität/Kompatibilität migration Grund dafür ist auch der Grund, warum jetzt die Collections-API unterstützt Generika und die gleiche geblieben, und es ist nicht (wie in C#, wenn Sie eingeführt Generika) einen kompletten neuen Satz von generischen bewusst Collection-API.
Die Kompatibilität wurde mit ersure (generischer Typ-parameter-info entfernt zur compile-Zeit), das ist auch der Grund, warum Sie so viele unchecked cast-Warnungen in java.
Könnte man noch hinzufügen, vergegenständlicht Generika aber es ist nicht so einfach. Einfach nur mit dem Typ info add Laufzeit statt es zu entfernen wird nicht funktionieren, da es nicht bricht, Quelle & Binär-Kompatibilität (Sie können nicht weiter verwenden raw-Typen, und Sie können nicht nennen vorhandenen kompilierten code, weil Sie nicht über die entsprechenden Methoden).
Der andere Ansatz ist der einer C# gewählt haben: siehe oben
Automatisierte und autoboxing/unboxing nicht unterstützt, für diesen Anwendungsfall, da autoboxing zu viel kostet.
Java-Theorie und Praxis: Generika Fallstricke
Allen nicht-array nicht-string-Objekt auf dem heap enthält eine 8 - oder 16-byte-header (Größen für 32/64-bit Systeme), gefolgt von dem Inhalt des Objekts öffentlichen und privaten Bereichen. Arrays und strings haben die oben genannten header, plus einige mehr bytes definieren die Länge des Arrays und die Größe der einzelnen Elemente (und gegebenenfalls die Anzahl der Dimensionen, der Länge jedes zusätzliche dimension, etc.), gefolgt von allen Bereichen das erste element, dann alle Felder der zweiten, etc. Gegeben eine Referenz auf ein Objekt, das system kann leicht überprüfen Sie den header und bestimmen, welche Art es ist.
Referenz-Typ Lagerorte halten Sie ein vier - oder acht-byte-Wert, der eindeutig identifiziert ein Objekt auf dem heap. In gegenwärtigen Implementierungen dieser Wert ist ein Zeiger, aber es ist einfacher (und semantisch gleichwertig) zu denken, der es als "Objekt-ID".
Wert-Typ Lagerorte halten Sie den Inhalt des value-Typs Felder, aber Sie haben nicht alle notwendigen header. Wenn der code deklariert eine variable vom Typ
Int32
gibt es keine Notwendigkeit brauchen, um Informationen zu speichern, mit, dassInt32
sagen, was es ist. Die Tatsache, dass die location hält eineInt32
wird effektiv gespeichert, die als Teil des Programms, und so ist es nicht gespeichert werden müssen, in die Lage selbst. Das eine darstellen, eine große Einsparungen, wenn, z.B., hat man eine million Objekte, von denen jedes ein Feld vom TypInt32
. Die einzelnen Objekte hält dieInt32
hat einen header identifiziert die Klasse, zu bedienen. Da ein Exemplar der Klasse code kann auf jede von den Millionen Fällen ist die Tatsache, dass das Feld einInt32
Teil des Codes ist viel effizienter, als wenn der Speicher für jedes dieser Felder enthalten Informationen darüber, was es ist.Boxen ist erforderlich, wenn ein Antrag auf Weitergabe der Inhalte eines Wert-Typ Lagerort zu code, der nicht weiß, zu erwarten, dass insbesondere ein Wert-Typ. Code, der erwartet, dass Objekte unbekannten Typs annehmen kann, eine Referenz auf ein Objekt auf dem heap. Da jedes Objekt auf dem heap hat einen header zu identifizieren, welche Art von Objekt es sich handelt, können Sie code verwenden, die header-Wann immer es notwendig ist, ein Objekt zu verwenden, in einer Weise, die erfordern würde, zu wissen, seine Art.
Beachten Sie, dass in .net, es möglich ist, zu erklären, was genannt werden generische Klassen und Methoden. Jede solche Erklärung generiert automatisch eine Familie von Klassen oder Methoden, die sind identisch, außer er fort Typ des Objekts, auf das Sie erwarten, zu handeln. Wenn man übergibt ein
Int32
zu einem routine -DoSomething<T>(T param)
, wird automatisch eine version der routine, in der jede Instanz des TypsT
ist effektiv ersetzt mitInt32
. Diese version der routine, wird wissen, dass jeder Lagerort deklariert als TypT
hält eineInt32
, also so wie in dem Fall, wo eine routine war hart codiert, um die Verwendung einerInt32
Speicherort, es wird nicht notwendig sein zum speichern von information in der Art mit diesen Orten selbst.In Java und C# (im Gegensatz zu C++) alles extends Object, also collection-Klassen wie ArrayList halten kann-Objekt oder eines seiner Nachkommen (im Grunde alles).
Aus performance-Gründen, aber primitive in java-oder Werttypen in C#, erhielten einen besonderen status. Sie sind nicht Objekt. Sie etwas nicht tun kann, wie (in Java):
Obwohl toString ist eine Methode auf dem Objekt. Damit überbrücken Sie diese kräftig an Leistung, gleichwertige Objekte erstellt wurden. AutoBoxing entfernt den boilerplate-code zu haben um eine primitive, der in seine wrapper-Klasse und nehmen es wieder heraus, macht den code lesbarer zu gestalten.
Den Unterschied zwischen Wert-Typen und Objekte in C# ist mehr Grau. Sehen hier darüber, wie Sie anders sind.