Чому ми використовуємо автопакування та розпаковування в 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.