Чому ми використовуємо автопакування та розпаковування в Java?


81

Автобокс - це автоматичне перетворення, яке компілятор Java робить між примітивними типами та відповідними класами обгортки об’єктів. Наприклад, перетворення int у ціле число, double у подвійне тощо. Якщо перетворення йде іншим шляхом, це називається розпаковуванням.

То навіщо нам це потрібно і чому ми використовуємо автобоксинг та розпаковування в Java?


1
В основному для
— дженериків

3
Integerє parseIntметод. intне має. :)
— Vishal Zanzrukia

@VishalZanzrukia Тож для отримання більшої функціональності?

12
Можна мати List<Integer>, але не можна List<int>.
— Vishal Zanzrukia

Так .. точно .. щоб отримати більше функціональних можливостей
— Vishal Zanzrukia

Відповіді:


173

Для повного розуміння головної причини цього потрібен певний контекст.

Примітиви проти класів

Примітивні змінні в Java містять значення (ціле число, двійкове число з плаваючою комою з подвійною точністю тощо). Оскільки ці значення можуть мати різну довжину , змінні, що їх містять, також можуть мати різну довжину (враховуйте floatпроти double).

З іншого боку, змінні класу містять посилання на екземпляри. Посилання зазвичай реалізуються як покажчики (або щось дуже схоже на покажчики) на багатьох мовах. Ці речі , як правило , мають однаковий розмір, незалежно від розмірів випадків вони відносяться ( Object, String, Integerі т.д.).

Ця властивість змінних класу робить посилання, які вони містять, взаємозамінними (до певної міри). Це дозволяє нам робити те, що ми називаємо заміною : загалом кажучи, використовувати екземпляр певного типу як екземпляр іншого, пов'язаного типу (використовувати a Stringяк an 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це незручно, бувають випадки, коли мова робить це автоматично - це називається автобокс .


Відповідно до вашого пояснення, нам потрібні ці класи Integer, String, ... для реалізації дженериків. Чи є якась інша причина?
— Bishwas Mishra

1
@BishwasMishra У нас вони є, щоб ми могли використовувати ці значення як Objectекземпляри. Узагальнення за допомогою стирання типів - одне із них.
— Теодорос Чатсігіананкаіс,

16

Авто бокс буде використовуватися для перетворення примітивних типів даних до їх об'єктів класу обгортки. Клас обгортки забезпечує широкий спектр функцій, що виконуються на примітивних типах. Найпоширеніший приклад:

int a = 56;
Integer i = a; // Auto Boxing

Це потрібно, оскільки програмістам легко мати можливість безпосередньо писати код, а JVM подбає про бокс і розпакування.

Автобокс також стає в нагоді, коли ми працюємо з типами 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 . 

4

Примітивні (не об’єктні) типи мають виправдання щодо ефективності.

Первісні типи - int, boolean, doubleце безпосередні дані, тоді як Objects - посилання. Звідси поля (або змінні)

int i;
double x;
Object s;

потрібна локальна пам’ять 4 + 8 + 8? де для об’єкта зберігається лише посилання (адреса) на пам’ять.

Використовуючи обгортки Object Integer, Doubleта інші, можна було б ввести опосередкованість, посилання на деякий екземпляр Integer / Double у купі пам'яті.

Навіщо потрібен бокс?

Це питання щодо відносного масштабу. У майбутньому java планується мати можливість ArrayList<int>підняти примітивні типи.

Відповідь: На даний момент ArrayList працює лише для Object, резервуючи місце для посилання на об'єкт та керуючи збором сміття. Отже, загальні типи - це діти-об'єкти. Отже, якщо хтось хотів мати ArrayList значень з плаваючою комою, потрібно було обернути подвійне в об’єкт Double.

Тут Java відрізняється від традиційного C ++ своїми шаблонами: класи C ++ vector<string>, vector<int>створюють два продукти компіляції. Дизайн Java використовував один ArrayList.class, не потребуючи для кожного типу параметрів новий скомпільований продукт.

Тож без боксу до Object потрібно було б компілювати класи для кожного входження типу параметра. Concreto: кожна колекція або клас контейнера потребуватиме версії для Object, int, double, boolean. Версія Object буде обробляти всі дочірні класи.

Насправді потреба в такій диверсифікації вже існувала в Java SE для IntBuffer, CharBuffer, DoubleBuffer, ... які працюють на int, char, double. Це було вирішено хакерським шляхом шляхом генерування цих джерел із загального.


4

Починаючи з JDK 5, Java додала дві важливі функції: автобокс та автобокс. AutoBoxing - це процес, для якого примітивний тип автоматично інкапсулюється в еквівалентну обгортку, коли потрібен такий об’єкт. Вам не потрібно явно будувати об’єкт. Автоматичне розпаковування - це процес, за допомогою якого значення інкапсульованого об’єкта автоматично витягується з обгортки типу, коли потрібно його значення. Вам не потрібно викликати такий метод, як intValue () або doubleValue () .

Додавання автобоксингу та автоматичного розпаковування значно спрощує алгоритми написання , виключаючи приманку вручну боксувати та розпаковувати значення. Також корисно уникати помилок . Це також дуже важливо для дженериків , які оперують лише об’єктами. Нарешті, автобокс полегшує роботу з Framework Collections .


2

чому у нас (не) бокс?

зробити написання коду там, де ми поєднуємо примітиви та їх об’єктно-орієнтовані (ОО) альтернативи, більш зручним / менш детальним.

чому ми маємо примітиви та їх альтернативи ОО?

примітивні типи не є класами (на відміну від C #), отже, вони не є підкласами Objectта не можуть бути замінені.

у нас є примітиви, як intз міркувань продуктивності, так і Objectальтернативи, такі Integerяк переваги програмування ОО, і як другорядний момент, щоб мати гарне місце для констант та методів утиліти (Integer.MAX_VALUE та Integer.toString(int)).

Переваги OO легше всього помітити в Generics ( List<Integer>), але не обмежуючись цим, наприклад:

Number getMeSome(boolean wantInt) {

    if (wantInt) {
        return Integer.MAX_VALUE;
    } else {
        return Long.MAX_VALUE;
    }
}

1

Деякі структури даних можуть приймати лише об'єкти, жодних примітивних типів.

Приклад: ключ у HashMap.

Докладніше див. У цьому питанні: HashMap та int як ключ

Є й інші вагомі причини, такі як поле "int" у базі даних, яке також може мати значення NULL. Int у Java не може бути нульовим; посилання на ціле число може. Автопакування та розпакування забезпечують можливість уникнути введення сторонніх кодів у перетворення вперед і назад.


0

Тому що вони бувають різних типів, і як зручність. Швидше за все продуктивність є причиною виникнення примітивних типів.


0

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));автобокс.

Аналогічно для отримання значення ми просто вводимо intArrayList.get (0) і компілятор, який перетворює на <code>intArrayList.get(0).intValue();autoUnboxing.


0

Автобокс: Перетворення примітивного значення в об’єкт відповідного класу обгортки.

Розпакування: Перетворення об’єкта типу обгортки у відповідне примітивне значення

// 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); 

    } 
} 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.