Автобоксирование - это автоматическое преобразование, которое компилятор Java выполняет между примитивными типами и соответствующими им классами-оболочками объектов. Например, преобразование int в Integer, double в Double и так далее. Если преобразование идет другим путем, это называется распаковкой.
Так зачем нам это нужно и почему мы используем автобоксирование и распаковку в Java?
java
autoboxing
Теодорос Хатцигианнакис
источник
источник
Integer
естьparseInt
метод.int
не имеет. :)List<Integer>
, но не можетеList<int>
.Ответы:
Необходим некоторый контекст, чтобы полностью понять основную причину этого.
Примитивы против классов
Примитивные переменные в Java содержат значения (целое число, двоичное число с плавающей запятой двойной точности и т. Д.). Поскольку эти значения могут иметь разную длину , переменные, содержащие их, также могут иметь разную длину (рассмотрим по
float
сравнению сdouble
).С другой стороны, переменные класса содержат ссылки на экземпляры. Ссылки обычно реализуются как указатели (или что-то очень похожее на указатели) на многих языках. Эти вещи , как правило , имеют одинаковый размер, независимо от размеров случаев они относятся (
Object
,String
,Integer
и т.д.).Это свойство переменных класса делает ссылки, которые они содержат, взаимозаменяемыми (в определенной степени). Это позволяет нам делать то, что мы называем подстановкой : вообще говоря, использовать экземпляр определенного типа как экземпляр другого, связанного типа (например, использовать a
String
как anObject
).Примитивные переменные не взаимозаменяемы одинаково ни друг с другом, ни с
Object
. Наиболее очевидная причина (но не единственная) - разница в размерах. Это делает примитивные типы неудобными в этом отношении, но они все еще нужны нам в языке (по причинам, которые в основном сводятся к производительности).Дженерики и стирание типов
Универсальные типы - это типы с одним или несколькими параметрами типа (точное число называется универсальной арностью ). Например, определение универсального типа
List<T>
имеет параметр типаT
, который может бытьObject
(создание конкретного типаList<Object>
),String
(List<String>
),Integer
(List<Integer>
) и так далее.Универсальные типы намного сложнее неуниверсальных. Когда они были представлены Java (после ее первоначального выпуска), чтобы избежать радикальных изменений JVM и возможного нарушения совместимости со старыми двоичными файлами, создатели Java решили реализовать универсальные типы наименее инвазивным способом: все конкретные типы
List<T>
на самом деле скомпилированы в (двоичный эквивалент)List<Object>
(для других типов граница может быть чем-то другимObject
, но вы понимаете). В этом процессе теряется общая информация о параметрах арности и типа , поэтому мы называем это стиранием типа .Соединение двух вместе
Теперь проблема заключается в сочетании перечисленных выше реалий: если
List<T>
становитсяList<Object>
во всех случаях, тоT
всегда должен быть тип, которому можно напрямую присвоитьObject
. Ничего другого нельзя допускать. Поскольку, как мы уже говорили ранее,int
,float
иdouble
не являются взаимозаменяемымиObject
, может не бытьList<int>
,List<float>
илиList<double>
(если значительно более сложная реализация дженериков не существовало в JVM).Но Java типы таких предложений
Integer
,Float
иDouble
которые обернуть эти примитивы в экземпляры класса, что делает их эффективно взаимозаменяемы , какObject
, таким образом , позволяя общие типы , косвенно работы с примитивами , как хорошо (потому что вы можете иметьList<Integer>
,List<Float>
,List<Double>
и так далее).Процесс создания
Integer
изint
a,Float
afloat
и т. Д. Называется боксом . Обратное называется распаковкой . Поскольку необходимость упаковывать примитивы каждый раз, когда вы хотите их использоватьObject
, неудобно, бывают случаи, когда язык делает это автоматически - это называется автобоксингом .источник
Object
экземпляров. Обобщение через стирание типа - одно из применений этого.Авто бокс будет использоваться для преобразования примитивных типов данных к их объектам класса обертки. Класс Wrapper предоставляет широкий спектр функций, выполняемых над примитивными типами. Самый распространенный пример:
int a = 56; Integer i = a; // Auto Boxing
Это необходимо потому что программисты легко могут напрямую писать код, а JVM позаботится о упаковке и распаковке.
Auto Boxing также пригодится, когда мы работаем с типами java.util.Collection. Когда мы хотим создать коллекцию примитивных типов, мы не можем напрямую создать коллекцию примитивного типа, мы можем создать коллекцию только объектов. Например :
ArrayList<int> al = new ArrayList<int>(); // not supported ArrayList<Integer> al = new ArrayList<Integer>(); // supported al.add(45); //auto Boxing
Классы обертки
Каждый из 8 примитивных типов Java (byte, short, int, float, char, double, boolean, long) имеет отдельный класс Wrapper, связанный с ними. Этот класс Wrapper имеет предопределенные методы для выполнения полезных операций с примитивными типами данных.
Использование классов оболочки
String s = "45"; int a = Integer.parseInt(s); // sets the value of a to 45.
Классы Wrapper предоставляют множество полезных функций. Ознакомьтесь с документацией по Java здесь
Распаковка противоположна Auto Boxing, где мы преобразуем объект класса оболочки обратно в его примитивный тип. JVM делает это автоматически, поэтому мы можем использовать классы-оболочки для определенных операций, а затем преобразовывать их обратно в примитивные типы, поскольку примитивы приводят к более быстрой обработке. Например :
Integer s = 45; int a = s; auto UnBoxing;
В случае Коллекций, которые работают с объектами, используется только автоматическая распаковка. Вот как :
ArrayList<Integer> al = new ArrayList<Integer>(); al.add(45); int a = al.get(0); // returns the object of Integer . Automatically Unboxed .
источник
Примитивные (не объектные) типы имеют здесь свою эффективность.
Примитивные типы
int, boolean, double
- это непосредственные данные, аObject
s - ссылки. Следовательно, поля (или переменные)int i; double x; Object s;
потребуется локальная память 4 + 8 + 8? где для объекта хранится только ссылка (адрес) на память.
Используя обертки Object
Integer, Double
и другие, можно было бы ввести косвенную ссылку на некоторый экземпляр Integer / Double в памяти кучи.Зачем нужен бокс?
Это вопрос относительного масштаба. Планируется, что в будущем Java будет иметь возможность
ArrayList<int>
поднимать примитивные типы.Ответ: на данный момент ArrayList работает только для объекта, резервируя место для ссылки на объект и аналогичным образом управляя сборкой мусора. Следовательно, универсальные типы являются дочерними объектами. Итак, если кому-то нужен ArrayList значений с плавающей запятой, нужно было обернуть двойное значение в объект Double.
Здесь Java отличается от традиционного C ++ своими шаблонами: классы C ++
vector<string>, vector<int>
создают два продукта компиляции. В Java-дизайне использовался один ArrayList.class, и для каждого типа параметра не требовался новый скомпилированный продукт.Таким образом, без упаковки в объект нужно было бы компилировать классы для каждого вхождения типа параметра. Конкретно: каждой коллекции или классу контейнера потребуется версия для Object, int, double, boolean. Версия для Object будет обрабатывать все дочерние классы.
Фактически, потребность в такой диверсификации уже существовала в Java SE для IntBuffer, CharBuffer, DoubleBuffer, ... которые работают с int, char, double. Это было решено хакерским способом путем генерации этих исходников из общего.
источник
Начиная с JDK 5, в java добавлены две важные функции: автобоксинг и автоотборка. AutoBoxing - это процесс, для которого примитивный тип автоматически инкапсулируется в эквивалентную оболочку всякий раз, когда требуется такой объект. Вам не нужно явно создавать объект. Автоматическая распаковка - это процесс, при котором значение инкапсулированного объекта автоматически извлекается из оболочки типа, когда требуется его значение. Вам не нужно вызывать такие методы, как intValue () или doubleValue () .
Добавление автобокса и автоматической распаковки значительно упрощает алгоритмы записи , устраняя приманку ручную упаковку и распаковку значений. Также полезно избегать ошибок . Это также очень важно для дженериков , которые работают только с объектами. Наконец, автобокс облегчает работу с Collections Framework .
источник
почему у нас (не) бокс?
сделать написание кода, в котором мы смешиваем примитивы и их объектно-ориентированные (OO) альтернативы, более удобным / менее подробным.
почему у нас есть примитивы и их объектно-ориентированные альтернативы?
примитивные типы не являются классами (в отличие от C #), поэтому они не являются подклассами
Object
и не могут быть переопределены.у нас есть примитивы, например,
int
по соображениям производительности, иObject
альтернативы, например,Integer
для преимуществ объектно-ориентированного программирования, и, как второстепенный момент, чтобы иметь хорошее место для служебных констант и методов (Integer.MAX_VALUE иInteger.toString(int)
).Преимущества объектно-ориентированного программирования легче всего увидеть с помощью Generics (
List<Integer>
), но не ограничиваются этим, например:Number getMeSome(boolean wantInt) { if (wantInt) { return Integer.MAX_VALUE; } else { return Long.MAX_VALUE; } }
источник
Некоторые структуры данных могут принимать только объекты, но не примитивные типы.
Пример: ключ в HashMap.
См. Этот вопрос для получения дополнительной информации: HashMap и int как ключ
Есть и другие веские причины, например, поле "int" в базе данных, которое также может иметь значение NULL. Тип int в Java не может быть нулевым; целочисленная ссылка может. Автобоксирование и распаковка позволяют избежать написания постороннего кода при преобразованиях туда и обратно.
источник
Потому что они разных типов и для удобства. Вероятно, производительность является причиной наличия примитивных типов.
источник
ArrayList не поддерживает примитивные типы, только класс поддержки. но нам нужно использовать примитивные типы, например int, double и т. д.
ArrayList<String> strArrayList = new ArrayList<String>(); // is accepted. ArrayList<int> intArrayList = new ArrayList<int>(); // not accepted.
Класс Integer оборачивает значение примитивного типа int в объект, поэтому следующий код принимается.
ArrayList<Integer> intArrayList = new ArrayList<Integer>(); // is accepted.
мы можем добавить значение с помощью метода add (value). Чтобы добавить строковое значение, скажите «Привет» в коде strArrayList, это просто
strArrayList.add("Hello");
и добавьте значение int, скажем 54, мы можем написать
intArrayList.add(54);
но когда мы пишем intArrayList.add (54); компилятор преобразовать в следующую строку
intArrayList.add(Integer.valueOf(54));
Поскольку intArrayList.add (54) проще и более приемлемо со стороны пользователя, компилятор выполняет тяжелую работу, а
intArrayList.add(Integer.valueOf(54));
именно - autoBoxing.Аналогично, чтобы получить значение, мы просто набираем intArrayList.get (0), и компилятор преобразует его в
<code>intArrayList.get(0).intValue();
autoUnboxing.источник
Автобоксинг: преобразование примитивного значения в объект соответствующего класса-оболочки.
Распаковка: преобразование объекта типа оболочки в соответствующее примитивное значение
// Java program to illustrate the concept // of Autoboxing and Unboxing import java.io.*; class GFG { public static void main (String[] args) { // creating an Integer Object // with value 10. Integer i = new Integer(10); // unboxing the Object int i1 = i; System.out.println("Value of i: " + i); System.out.println("Value of i1: " + i1); //Autoboxing of char Character gfg = 'a'; // Auto-unboxing of Character char ch = gfg; System.out.println("Value of ch: " + ch); System.out.println("Value of gfg: " + gfg); } }
источник