Почему мы используем autoboxing и unboxing в Java?
Автобокс - это автоматическое преобразование, которое выполняет компилятор Java между примитивными типами и их соответствующими классами-обертками объектов. Например, преобразование целого числа в целое, двойное в двойное и т. Д. Если преобразование идет другим путем, это называется распаковкой.
Так зачем нам это нужно и почему мы используем autoboxing и unboxing в Java?
10 ответов
Некоторый контекст необходим, чтобы полностью понять основную причину этого.
Примитивы против классов
Примитивные переменные в Java содержат значения (целое число, двоичное число с плавающей запятой двойной точности и т. Д.). Поскольку эти значения могут иметь разную длину, переменные, содержащие их, могут также иметь разную длину (рассмотрим float
против double
).
С другой стороны, переменные класса содержат ссылки на экземпляры. Ссылки обычно реализуются как указатели (или что-то очень похожее на указатели) во многих языках. Эти вещи обычно имеют одинаковый размер, независимо от размеров экземпляров, на которые они ссылаются (Object
, String
, Integer
, так далее).
Это свойство переменных класса делает ссылки, которые они содержат, взаимозаменяемыми (в некоторой степени). Это позволяет нам делать то, что мы называем заменой: в общем, использовать экземпляр определенного типа как экземпляр другого, связанного типа (используйте String
как Object
, например).
Примитивные переменные не взаимозаменяемы ни друг с другом, ни с 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
, Float
из float
и так далее, называется боксом. Обратное называется распаковкой. Потому что нужно приставлять примитивы каждый раз, когда вы хотите использовать их как Object
неудобно, есть случаи, когда язык делает это автоматически - это называется автобоксом.
Auto Boxing используется для преобразования примитивных типов данных в объекты классов-оболочек. Класс 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 имеют предопределенные методы для предварительной обработки полезных операций над примитивными типами данных.
Использование классов 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? где для объекта хранится только ссылка (адрес) на память.
Использование обёрток объекта Integer, Double
и другие, можно было бы ввести косвенную ссылку на некоторый экземпляр типа Integer/Double в памяти кучи.
Зачем нужен бокс?
Это вопрос относительной сферы. В будущем Java планируется иметь возможность иметь ArrayList<int>
Подъем примитивных типов.
Ответ: В настоящее время ArrayList работает только для Object, резервируя место для ссылки на объект и аналогично управляя сборкой мусора. Следовательно, универсальные типы являются дочерними объектами. Поэтому, если кто-то хочет ArrayList значений с плавающей запятой, нужно обернуть double в объект 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 добавлены две важные функции: автобокс и автобокс. Автобокс - это процесс, для которого примитивный тип автоматически инкапсулируется в эквивалентную оболочку всякий раз, когда такой объект необходим. Вам не нужно явно создавать объект. Автоматическая распаковка - это процесс, при котором значение инкапсулированного объекта автоматически извлекается из оболочки типа, когда требуется его значение. Вам не нужно вызывать такой метод, как intValue() или doubleValue ().
Добавление автобоксов и автоматических распаковок значительно упрощает написание алгоритмов, устраняя приманку, упаковывая вручную и распаковывая значения. Также полезно избегать ошибок. Это также очень важно для генериков, которые работают только с объектами. Наконец, автобокс облегчает работу с коллекцией Framework.
Некоторые структуры данных могут принимать только объекты, без примитивных типов.
Пример: ключ в HashMap.
Смотрите этот вопрос для более: HashMap и Int в качестве ключа
Есть и другие веские причины, такие как поле int в базе данных, которое также может иметь значение NULL. Int в Java не может быть нулевым; Ссылка на целое число может. Автобокс и распаковка дают возможность избежать написания постороннего кода в конверсиях туда-сюда.
почему у нас есть (не) бокс?
сделать написание кода, в котором мы смешиваем примитивы и их объектно-ориентированные (OO) альтернативы, более удобным / менее многословным.
почему у нас есть примитивы и их альтернативы 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;
}
}
Потому что они разных типов и как удобство. Производительность, скорее всего, является причиной появления примитивных типов.
ArrayList не поддерживает примитивные типы, только поддерживает класс. но нам нужно использовать примитивные типы, например, int, double и т. д.
ArrayList<String> strArrayList = new ArrayList<String>(); // is accepted.
ArrayList<int> intArrayList = new ArrayList<int>(); // not accepted.
Класс Integer оборачивает значение примитивного типа int в object.so, нижеприведенный код принят.
ArrayList<Integer> intArrayList = new ArrayList<Integer>(); // is accepted.
мы можем добавить значение с помощью метода add(value). Чтобы добавить значение String, скажите "Hello" в коде 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));
это автобокс.
Аналогично, чтобы получить значение, мы просто набираем 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);
}
}
Другой особый случай:
Integer intval = null;
int toPrimitive = intval;
System.out.println(toPrimitive);
Мы получаем
NullPointerException
для вышеуказанного сценария. это означает, что мы можем поймать NPE