Szukam jasnej, zwięzłej i dokładnej odpowiedzi.
Idealnie jako rzeczywista odpowiedź, chociaż mile widziane linki do dobrych wyjaśnień.
Szukam jasnej, zwięzłej i dokładnej odpowiedzi.
Idealnie jako rzeczywista odpowiedź, chociaż mile widziane linki do dobrych wyjaśnień.
language-but-not-type-agnostic
?static-language-agnostic
? Nie jestem pewien, czy SO potrzebuje rozróżnienia; może być jednak dobrym pytaniem do meta.Odpowiedzi:
Wartości w pudełkach to struktury danych, które są minimalnymi opakowaniami wokół typów pierwotnych *. Wartości w pudełkach są zwykle przechowywane jako wskaźniki do obiektów na stercie .
Tak więc wartości pudełkowe zajmują więcej pamięci i wymagają co najmniej dwóch wyszukiwań pamięci, aby uzyskać dostęp: raz, aby uzyskać wskaźnik, a drugi, aby podążać za tym wskaźnikiem do prymitywu. Oczywiście nie jest to coś, czego chcesz w swoich wewnętrznych pętlach. Z drugiej strony, wartości pudełkowe zazwyczaj lepiej współgrają z innymi typami w systemie. Ponieważ są to struktury danych pierwszej klasy w języku, mają oczekiwane metadane i strukturę, które mają inne struktury danych.
W Javie i Haskell kolekcje ogólne nie mogą zawierać wartości bez opakowania. Kolekcje ogólne w .NET mogą przechowywać wartości bez opakowania bez żadnych kar. Tam, gdzie typy ogólne języka Java są używane tylko do sprawdzania typów w czasie kompilacji, .NET wygeneruje określone klasy dla każdego typu ogólnego, którego wystąpienie jest tworzone w czasie wykonywania .
Java i Haskell mają tablice rozpakowane, ale są one znacznie mniej wygodne niż inne kolekcje. Jednak gdy potrzebna jest maksymalna wydajność, warto trochę niedogodności, aby uniknąć narzutu związanego z pakowaniem i rozpakowywaniem.
* W tej dyskusji wartością pierwotną jest każda wartość, która może być przechowywana na stosie wywołań , a nie jako wskaźnik do wartości na stercie. Często są to tylko typy maszyn (int, zmiennoprzecinkowe itp.), Struktury, a czasem tablice o statycznych rozmiarach. .NET-land nazywa je typami wartości (w przeciwieństwie do typów referencyjnych). Ludzie z Javy nazywają je typami prymitywnymi. Haskellions nazywają je po prostu rozpakowanymi.
** W tej odpowiedzi skupiam się również na Javie, Haskellu i C #, ponieważ to wiem. Warto wiedzieć, że Python, Ruby i Javascript mają wyłącznie wartości w pudełkach. Jest to również znane jako podejście „Wszystko jest obiektem” ***.
*** Uwaga: wystarczająco zaawansowany kompilator / JIT może w niektórych przypadkach faktycznie wykryć, że wartość, która jest zapakowana semantycznie podczas przeglądania źródła, może bezpiecznie być wartością rozpakowaną w czasie wykonywania. Krótko mówiąc, dzięki genialnym implementatorom języka, twoje skrzynki są czasami darmowe.
źródło
z C # 3.0 w pigułce :
źródło
Pakowanie i rozpakowywanie to proces konwertowania wartości pierwotnej na klasę opakowującą zorientowaną obiektowo (opakowanie) lub przekształcania wartości z klasy opakowującej zorientowanej obiektowo z powrotem na wartość pierwotną (rozpakowywanie).
Na przykład w Javie może być konieczne przekonwertowanie
int
wartości naInteger
(pudełko), jeśli chcesz ją przechowywać w a,Collection
ponieważ prymitywy nie mogą być przechowywane w aCollection
, tylko w obiektach. Ale kiedy chcesz odzyskać to z powrotem,Collection
możesz chcieć uzyskać wartość jako an,int
a nie an,Integer
więc powinieneś ją rozpakować.Boks i rozpakowywanie nie jest z natury złe , ale jest to kompromis. W zależności od implementacji języka może być wolniejszy i bardziej obciążający pamięć niż zwykłe używanie prymitywów. Jednak może również pozwolić na użycie struktur danych wyższego poziomu i osiągnięcie większej elastyczności w kodzie.
Obecnie jest to najczęściej omawiane w kontekście funkcji „autoboxing / autounboxing” Javy (i innych języków). Oto wyjaśnienie autoboxingu skoncentrowane na Javie .
źródło
W sieci:
Często nie można polegać na tym, jaki typ zmiennej będzie zużywać funkcja, więc trzeba użyć zmiennej obiektu, która rozciąga się od najniższego wspólnego mianownika - to jest .Net
object
.Jednak
object
jest to klasa i przechowuje swoją zawartość jako odniesienie.Chociaż oba zawierają te same informacje, druga lista jest dłuższa i wolniejsza. Każda wartość na drugiej liście jest w rzeczywistości odwołaniem do elementu
object
zawierającego rozszerzenieint
.Nazywa się to pudełkiem, ponieważ
int
jest opakowane przezobject
. Kiedyint
zostanie odrzucony, zostanie rozpakowany - przekonwertowany z powrotem na swoją wartość.W przypadku typów wartości (tj. Wszystkich
structs
) jest to powolne i potencjalnie zajmuje dużo więcej miejsca.W przypadku typów referencyjnych (tj. Wszystkich
classes
) jest to znacznie mniejszy problem, ponieważ i tak są one przechowywane jako referencje.Kolejnym problemem związanym z typem wartości w pudełku jest to, że nie jest oczywiste, że masz do czynienia z pudełkiem, a nie z wartością. Kiedy porównujesz dwie
structs
, porównujesz wartości, ale kiedy porównujesz dwie,classes
wtedy (domyślnie) porównujesz odniesienie - tj. Czy to jest ta sama instancja?Może to być mylące, gdy mamy do czynienia z opakowanymi typami wartości:
Łatwo jest obejść:
Jednak w przypadku wartości pudełkowych należy zachować ostrożność.
źródło
Object
nie implementuje operatora równości, ale typy klas można porównać zIs
operatorem; odwrotnie,Int32
może być używany z operatorem równości, ale nieIs
. To rozróżnienie sprawia, że dużo jaśniej jest, jakiego rodzaju porównania dokonuje się.Boxing
jest procesem konwersji typu wartości na typ referencyjny. NatomiastUnboxing
jest to konwersja typu referencyjnego na typ wartościowy.Typy wartości to:
int
,char
istructures
,enumerations
. Typy referencyjne są następujące:Classes
,interfaces
,arrays
,strings
iobjects
źródło
Kolekcje ogólne .NET FCL:
wszystkie zostały zaprojektowane, aby przezwyciężyć problemy z wydajnością pakowania i rozpakowywania w poprzednich implementacjach kolekcji.
Aby uzyskać więcej informacji, zobacz rozdział 16, CLR przez C # (wydanie drugie) .
źródło
Pakowanie i rozpakowywanie ułatwia traktowanie typów wartości jako obiektów. Boks oznacza konwersję wartości na wystąpienie typu odwołania do obiektu. Na przykład
Int
jest klasą iint
jest typem danych. Konwersjaint
naInt
jest przykładem boksu, podczas gdy konwersjaInt
naint
jest rozpakowywaniem. Koncepcja pomaga w wyrzucaniu elementów bezużytecznych, z drugiej strony Unboxing konwertuje typ obiektu na typ wartości.źródło
var ii = 123; typeof ii
zwracanumber
.var iiObj = new Number(123); typeof iiObj
zwracaobject
.typeof ii + iiObj
zwracanumber
. To jest odpowiednik boksu w javascript. Wartość iiObj została automatycznie przekonwertowana na liczbę pierwotną (bez opakowania) w celu wykonania arytmetyki i zwrócenia wartości bez opakowania.Jak wszystko inne, autoboxing może być problematyczny, jeśli nie jest używany ostrożnie. Klasyczne jest to, że kończy się wyjątek NullPointerException i nie można go wyśledzić. Nawet z debugerem. Spróbuj tego:
źródło
i
została przedwcześnie zainicjalizowana. Albo uczyń ją pustą deklaracją (Integer i;
), aby kompilator mógł wskazać, że zapomniałeś jej zainicjować, albo poczekaj z zadeklarowaniem, aż poznasz jej wartość.