@HenkHolterman это определенно не зависит от языка, хотя это также не относится ко всем языкам - например, это различие не будет иметь значения для большинства языков с динамической типизацией. Я не уверен, какой тег можно использовать вместо - language-but-not-type-agnostic? static-language-agnostic? Я не уверен, что ТАК нужно различие; может быть, хороший вопрос для мета, хотя.
Кит
Ответы:
189
Значения в штучной упаковке - это структуры данных, которые являются минимальными оболочками вокруг примитивных типов *. В штучной упаковке значения обычно хранятся в виде указателей на объекты в куче .
Таким образом, значения в штучной упаковке используют больше памяти и требуют как минимум два поиска в памяти: один - для получения указателя, а другой - для того, чтобы следовать этому указателю на примитив. Очевидно, это не та вещь, которую вы хотите в своих внутренних циклах. С другой стороны, значения в штучной упаковке обычно лучше работают с другими типами в системе. Так как они являются первоклассными структурами данных в языке, они имеют ожидаемые метаданные и структуру, которые имеют другие структуры данных.
Java и Haskell имеют распакованные массивы, но они явно менее удобны, чем другие коллекции. Однако, когда требуется максимальная производительность, стоит немного неудобств, чтобы избежать накладных расходов на упаковку и распаковку.
* Для этого обсуждения примитивное значение - это любое, которое может быть сохранено в стеке вызовов , а не сохранено как указатель на значение в куче. Часто это просто типы машин (целые, плавающие и т. Д.), Структуры, а иногда и статические массивы. .NET-land называет их типами значений (в отличие от ссылочных типов). Java-люди называют их примитивными типами. Хаскеллионы просто называют их без коробки.
** В этом ответе я также фокусируюсь на Java, Haskell и C #, потому что это то, что я знаю. Для чего бы это ни стоило, Python, Ruby и Javascript имеют исключительно упакованные значения. Это также известно как подход «Все является объектом» ***.
*** Предостережение: достаточно продвинутый компилятор / JIT может в некоторых случаях фактически обнаружить, что значение, которое семантически упаковано при взгляде на источник, может безопасно быть распакованным значением во время выполнения. По сути, благодаря блестящим языковым разработчикам ваши ящики иногда свободны.
Почему, хотя в штучной упаковке, какое преимущество дает CLR или что-то еще, получающее значения в форме бокса?
PositiveGuy
Короче говоря (ха-ха), это просто еще один объект, который очень удобен. Примитивы (по крайней мере, в Java) не происходят от Object, не могут иметь полей, не могут иметь методов и просто ведут себя совершенно иначе, чем другие типы значений. С другой стороны, работа с ними может быть очень быстрой и экономичной. Таким образом, компромисс.
Питер Бернс
2
Javascript имеет так называемые типизированные массивы (новый UInt32Array и т. Д.), Которые представляют собой массивы распакованных целочисленных значений и чисел с плавающей точкой.
Упаковка и распаковка - это процесс преобразования примитивного значения в объектно-ориентированный класс-оболочку (бокс) или преобразование значения из объектно-ориентированного класса-оболочки обратно в примитивное значение (распаковка).
Например, в Java вам может понадобиться преобразовать intзначение в Integer(бокс), если вы хотите сохранить его в, Collectionпотому что примитивы не могут быть сохранены Collectionтолько в объектах. Но когда вы хотите получить его обратно, Collectionвы можете получить значение как, intа не как, Integerчтобы распаковать его.
Бокс и распаковка - это не плохо , но это компромисс. В зависимости от языковой реализации, он может быть медленнее и занимать больше памяти, чем просто использование примитивов. Однако это также может позволить вам использовать структуры данных более высокого уровня и достичь большей гибкости в вашем коде.
Часто вы не можете полагаться на тип переменной, которую будет использовать функция, поэтому вам нужно использовать переменную объекта, которая начинается с наименьшего общего знаменателя - в .Net это object .
Однако objectявляется классом и хранит его содержимое в качестве ссылки.
List<int> notBoxed = new List<int> { 1, 2, 3 };
int i = notBoxed[1]; // this is the actual value
List<object> boxed = new List<object> { 1, 2, 3 };
int j = (int) boxed[1]; // this is an object that can be 'unboxed' to an int
Хотя оба они содержат одинаковую информацию, второй список больше и медленнее. Каждое значение во втором списке на самом деле является ссылкой objectнаint .
Это называется в штучной упаковке, потому что intобернут в object. Когда его отброситьint распаковывается, оно преобразуется обратно в его значение.
Для типов значений (т.е. всех structs ) это медленно и потенциально занимает гораздо больше места.
Для справочных типов (т.е. всех classes ) это гораздо меньше проблем, так как они все равно хранятся как ссылки.
Еще одна проблема с типом значений в штучной упаковке заключается в том, что не очевидно, что вы имеете дело с блоком, а не со значением. Когда вы сравниваете два, structsтогда вы сравниваете значения, но когда вы сравниваете два, classesтогда (по умолчанию) вы сравниваете ссылку - т.е. это один и тот же экземпляр?
Это может сбивать с толку при работе с коробочными типами значений:
int a = 7;
int b = 7;
if(a == b) // Evaluates to true, because a and b have the same value
object c = (object) 7;
object d = (object) 7;
if(c == d) // Evaluates to false, because c and d are different instances
Это легко обойти:
if(c.Equals(d)) // Evaluates to true because it calls the underlying int's equals
if(((int) c) == ((int) d)) // Evaluates to true once the values are cast
Однако при работе со значениями в штучной упаковке следует соблюдать осторожность.
В vb.net различие между семантикой равенства более четкое, Objectне реализует оператор равенства, но типы классов можно сравнивать с Isоператором; и наоборот, Int32может использоваться с оператором равенства, но не Is. Это различие делает намного более ясным, какой тип сравнения делается.
суперкат
4
Boxingэто процесс преобразования типа значения в ссылочный тип. Принимая во внимание Unboxing, что преобразование ссылочного типа в тип значения.
EX: int i = 123;
object o = i;// Boxing
int j = (int)o;// UnBoxing
Упаковка и распаковка облегчает восприятие типов значений как объектов. Бокс означает преобразование значения в экземпляр ссылочного типа объекта. Например, Intявляется классом и intтипом данных. Преобразование intв Intявляется примером бокса, а преобразование Intв intраспаковку. Эта концепция помогает в сборке мусора. Распаковка, с другой стороны, преобразует тип объекта в тип значения.
int i=123;
object o=(object)i; //Boxing
o=123;
i=(int)o; //Unboxing.
В JavaScript var ii = 123; typeof ii возвращается number. var iiObj = new Number(123); typeof iiObjвозвращается object. typeof ii + iiObjвозвращается number. Так что это javascript-эквивалент бокса. Значение iiObj было автоматически преобразовано в примитивное число (без коробки), чтобы выполнить арифметику и вернуть значение без коробки.
PatS
-2
Как и все остальное, автобокс может быть проблематичным, если не использовать его осторожно. Классика заключается в том, чтобы получить исключение NullPointerException и не иметь возможности его отследить. Даже с отладчиком. Попробуй это:
public class TestAutoboxNPE
{
public static void main(String[] args)
{
Integer i = null;
// .. do some other stuff and forget to initialise i
i = addOne(i); // Whoa! NPE!
}
public static int addOne(int i)
{
return i + 1;
}
}
Это просто плохой код, и он не имеет ничего общего с автобоксом. Переменная iпреждевременно инициализирована. Либо сделайте его пустым объявлением ( Integer i;), чтобы компилятор мог указать, что вы забыли его инициализировать, либо дождитесь его объявления, пока не узнаете его значение.
Эриксон
Хм, и если я сделаю что-то промежуточное внутри блока try catch, то компилятор заставит меня что-то инициализировать. Это не настоящий код - это пример того, как это может произойти.
PEELY
Что это демонстрирует? Нет абсолютно никаких причин использовать объект Integer. Вместо этого вам теперь приходится иметь дело с потенциальным NullPointer.
language-but-not-type-agnostic
?static-language-agnostic
? Я не уверен, что ТАК нужно различие; может быть, хороший вопрос для мета, хотя.Ответы:
Значения в штучной упаковке - это структуры данных, которые являются минимальными оболочками вокруг примитивных типов *. В штучной упаковке значения обычно хранятся в виде указателей на объекты в куче .
Таким образом, значения в штучной упаковке используют больше памяти и требуют как минимум два поиска в памяти: один - для получения указателя, а другой - для того, чтобы следовать этому указателю на примитив. Очевидно, это не та вещь, которую вы хотите в своих внутренних циклах. С другой стороны, значения в штучной упаковке обычно лучше работают с другими типами в системе. Так как они являются первоклассными структурами данных в языке, они имеют ожидаемые метаданные и структуру, которые имеют другие структуры данных.
В Java и Haskell универсальные коллекции не могут содержать распакованных значений. Родовые коллекции в .NET могут содержать распакованные значения без штрафов. В тех случаях, когда дженерики Java используются только для проверки типов во время компиляции, .NET будет генерировать определенные классы для каждого родового типа, создаваемого во время выполнения .
Java и Haskell имеют распакованные массивы, но они явно менее удобны, чем другие коллекции. Однако, когда требуется максимальная производительность, стоит немного неудобств, чтобы избежать накладных расходов на упаковку и распаковку.
* Для этого обсуждения примитивное значение - это любое, которое может быть сохранено в стеке вызовов , а не сохранено как указатель на значение в куче. Часто это просто типы машин (целые, плавающие и т. Д.), Структуры, а иногда и статические массивы. .NET-land называет их типами значений (в отличие от ссылочных типов). Java-люди называют их примитивными типами. Хаскеллионы просто называют их без коробки.
** В этом ответе я также фокусируюсь на Java, Haskell и C #, потому что это то, что я знаю. Для чего бы это ни стоило, Python, Ruby и Javascript имеют исключительно упакованные значения. Это также известно как подход «Все является объектом» ***.
*** Предостережение: достаточно продвинутый компилятор / JIT может в некоторых случаях фактически обнаружить, что значение, которое семантически упаковано при взгляде на источник, может безопасно быть распакованным значением во время выполнения. По сути, благодаря блестящим языковым разработчикам ваши ящики иногда свободны.
источник
из C # 3.0 В двух словах :
источник
Упаковка и распаковка - это процесс преобразования примитивного значения в объектно-ориентированный класс-оболочку (бокс) или преобразование значения из объектно-ориентированного класса-оболочки обратно в примитивное значение (распаковка).
Например, в Java вам может понадобиться преобразовать
int
значение вInteger
(бокс), если вы хотите сохранить его в,Collection
потому что примитивы не могут быть сохраненыCollection
только в объектах. Но когда вы хотите получить его обратно,Collection
вы можете получить значение как,int
а не как,Integer
чтобы распаковать его.Бокс и распаковка - это не плохо , но это компромисс. В зависимости от языковой реализации, он может быть медленнее и занимать больше памяти, чем просто использование примитивов. Однако это также может позволить вам использовать структуры данных более высокого уровня и достичь большей гибкости в вашем коде.
В наши дни, это чаще всего обсуждается в контексте функции «autoboxing / autounboxing» Java (и других языков). Вот Java-ориентированное объяснение автобокса .
источник
В .Net:
Часто вы не можете полагаться на тип переменной, которую будет использовать функция, поэтому вам нужно использовать переменную объекта, которая начинается с наименьшего общего знаменателя - в .Net это
object
.Однако
object
является классом и хранит его содержимое в качестве ссылки.Хотя оба они содержат одинаковую информацию, второй список больше и медленнее. Каждое значение во втором списке на самом деле является ссылкой
object
наint
.Это называется в штучной упаковке, потому что
int
обернут вobject
. Когда его отброситьint
распаковывается, оно преобразуется обратно в его значение.Для типов значений (т.е. всех
structs
) это медленно и потенциально занимает гораздо больше места.Для справочных типов (т.е. всех
classes
) это гораздо меньше проблем, так как они все равно хранятся как ссылки.Еще одна проблема с типом значений в штучной упаковке заключается в том, что не очевидно, что вы имеете дело с блоком, а не со значением. Когда вы сравниваете два,
structs
тогда вы сравниваете значения, но когда вы сравниваете два,classes
тогда (по умолчанию) вы сравниваете ссылку - т.е. это один и тот же экземпляр?Это может сбивать с толку при работе с коробочными типами значений:
Это легко обойти:
Однако при работе со значениями в штучной упаковке следует соблюдать осторожность.
источник
Object
не реализует оператор равенства, но типы классов можно сравнивать сIs
оператором; и наоборот,Int32
может использоваться с оператором равенства, но неIs
. Это различие делает намного более ясным, какой тип сравнения делается.Boxing
это процесс преобразования типа значения в ссылочный тип. Принимая во вниманиеUnboxing
, что преобразование ссылочного типа в тип значения.Типы значений являются:
int
,char
иstructures
,enumerations
. Ссылочные типы являются:Classes
,interfaces
,arrays
,strings
иobjects
источник
Общие коллекции .NET FCL:
все они были разработаны для преодоления проблем с производительностью упаковки и распаковки в предыдущих реализациях коллекции.
Для получения дополнительной информации см. Главу 16, CLR через C # (2-е издание) .
источник
Упаковка и распаковка облегчает восприятие типов значений как объектов. Бокс означает преобразование значения в экземпляр ссылочного типа объекта. Например,
Int
является классом иint
типом данных. Преобразованиеint
вInt
является примером бокса, а преобразованиеInt
вint
распаковку. Эта концепция помогает в сборке мусора. Распаковка, с другой стороны, преобразует тип объекта в тип значения.источник
var ii = 123; typeof ii
возвращаетсяnumber
.var iiObj = new Number(123); typeof iiObj
возвращаетсяobject
.typeof ii + iiObj
возвращаетсяnumber
. Так что это javascript-эквивалент бокса. Значение iiObj было автоматически преобразовано в примитивное число (без коробки), чтобы выполнить арифметику и вернуть значение без коробки.Как и все остальное, автобокс может быть проблематичным, если не использовать его осторожно. Классика заключается в том, чтобы получить исключение NullPointerException и не иметь возможности его отследить. Даже с отладчиком. Попробуй это:
источник
i
преждевременно инициализирована. Либо сделайте его пустым объявлением (Integer i;
), чтобы компилятор мог указать, что вы забыли его инициализировать, либо дождитесь его объявления, пока не узнаете его значение.