обертка - объектные типы данных java
Java: зачем нужны классы-оболочки? (8)
На очень высоком уровне я знаю, что нам нужно «обернуть» примитивные типы данных, такие как int и char, используя их соответствующие классы-оболочки для их использования в коллекциях Java. Мне хотелось бы понять, как коллекции Java работают на низкий уровень, спросив: «Почему нам нужно обернуть примитивные типы данных в качестве объектов, чтобы использовать их в коллекциях?» Я заранее благодарю вас за вашу помощь.
В коллекции используются Generics. Framework Collection предназначен для сбора, хранения и обработки данных любого класса. Поэтому он использует общий тип. Используя Generics, он может хранить данные ЛЮБОГО КЛАССА, имя которого указано в его объявлении.
Теперь у нас есть различные сценарии, в которых нужно хранить примитивные данные таким же образом, в которых работает коллекция. У нас нет возможности хранить примитивные данные, используя классы Collection, такие как ArrayList, HashSet и т. Д., Потому что классы Collection могут хранить только объекты. Таким образом, для хранения примитивных типов в коллекции мы предоставляем классы-оболочки.
Если известно, что переменная имеет либо конкретный битовый шаблон, представляющий null либо информацию, которая может быть использована для поиска заголовка объекта виртуальной машины Java, и если метод чтения заголовка объекта, заданного ссылкой, по своей сути будет ловушкой, если задана битовая диаграмма связанный с null , то JVM может получить доступ к объекту, указанному переменной, в предположении, что он есть. Если переменная может содержать что-то, что не было действительной ссылкой, но не было конкретным шаблоном null бита, любой код, который пытался использовать эту переменную, должен был бы сначала проверить, идентифицировал ли он объект. Это значительно замедлит работу JVM.
Если Object полученный из Anything , и объекты класса, полученные из Object , но примитивы, унаследованные от другого класса, производного от Anything , тогда в 64-битной реализации может быть целесообразно сказать, что примерно 3/4 возможных битовых шаблонов будут представлять собой double значения ниже 2 ^ 512, 1/8 из них для представления long значений в диапазоне +/- 1,152,921,504,606,846,975, несколько миллиардов для представления любого возможного значения любого другого примитива и 1/256 для идентификации объектов. Многие виды операций над вещами типа Anything будут медленнее, чем с типом Object , но такие операции не будут ужасно частыми; большая часть кода закончит тем, Anything перед тем, как попытаться с ним работать, нужно лить Anything нибудь еще для определенного типа; фактический тип, хранящийся в « Anything , должен быть проверен перед литой, но не после выполнения броска. Тем не менее, отсутствие различия между переменной, содержащей ссылку на тип кучи, по сравнению с одним, содержащим «что-либо», не могло бы избежать того, чтобы накладные расходы расширялись значительно дальше, чем в противном случае.
На уровне виртуальной машины это связано с тем, что примитивные типы представлены по-разному в памяти по сравнению со ссылочными типами, такими как java.lang.Object и его производные типы. Примитивный int в Java, например, составляет всего 4 байта в памяти, тогда как Object занимает как минимум 8 байтов сам по себе, плюс еще 4 байта для его ссылки. Такой дизайн является простым отражением того факта, что процессоры могут обрабатывать примитивные типы намного эффективнее.
Поэтому один ответ на ваш вопрос «зачем нужны типы обертки» - это из-за повышения производительности, которое он дает.
Но для программистов такое различие добавляет некоторые нежелательные когнитивные накладные расходы (например, не может использовать int и float в коллекциях.) На самом деле, вполне возможно сделать дизайн языка, скрывая это различие - многие языки сценариев делают это, и CLR делает это. Начиная с 1.5, Java тоже делает это. Это достигается за счет того, что компилятор молча вводит необходимое преобразование между примитивным представлением и представлением объекта (которое обычно называют бокс / распаковкой).
Итак, еще один ответ на ваш вопрос: «Нет, нам это не нужно», потому что компилятор делает это автоматически для вас, и в определенной степени вы можете забыть, что происходит за сценой.
Ну, причина в том, что коллекции Java не различают примитив и объект. Он обрабатывает их все как Object, и поэтому ему понадобится обертка. Вы можете легко создать собственный класс коллекции, который не нуждается в оболочке, но в конце вам придется создавать по одному для каждого типа char, int, float, double и т. Д., Умножать на типы коллекций (Set, Map, Список + их реализация).
Можете ли вы представить себе, как это скучно?
И дело в том, что производительность, которую он приносит без использования обертки, практически не имеет значения для большинства приложений. Однако, если вам нужна очень высокая производительность, некоторые библиотеки для примитивных коллекций также доступны (например, http://www.joda.org/joda-primitives/ )
Поскольку коллекции Java могут хранить только ссылки на объекты (так что вам нужно вставить примитивы для их хранения в коллекциях).
Прочтите эту короткую статью об Autoboxing для получения дополнительной информации.
Если вы хотите подробные подробные сведения, это в значительной степени сводится к следующему:
Локальные примитивы хранятся в стеке. Коллекции хранят свои значения через ссылку на ячейку памяти объекта в куче. Чтобы получить эту ссылку для локального примитива, вам нужно вставить (принять значение в стеке и обернуть его для хранения в куче) значение.
Примитивные типы данных не могут быть указаны как адреса памяти. Вот почему нам нужны обертки, которые служат заполнителями для примитивных значений. Эти значения затем могут быть мутированы и доступны, реорганизованы, отсортированы или рандомизированы.
Это для C #, но та же концепция применима к Java. И Джон Скит написал ответ.
Чтобы сохранить значения примитивного типа в классах коллекции, нам требуется Wrapper classe.