Почему мы используем 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 являются непосредственными данными, тогда как Objects ссылки. Следовательно, поля (или переменные)

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

Другие вопросы по тегам