Автоупаковка і автораспаковка

Огляд оболонок типів і упаковки значень

Як вам відомо, в мові Java використовуються базові типи (також звані простими), такі як int або double, для зберігання елементарних даних типів, підтримуваних мовою. Для зберігання таких даних через більш високої продуктивності застосовуються базові типи, а не об'єкти. У цьому випадку використання об'єктів додає неприйнятні витрати навіть до найпростішої обчислювальної операції. Таким чином, базові типи не є частиною ієрархії об'єктів і не успадковують клас Object.

Незважаючи на виграш в продуктивності, пропонований базовими типами, виникають ситуації, що вимагають обов'язкового об'єктного уявлення. Наприклад, Ви не можете передати в метод змінну базового типу як параметр за посиланням. Крім того, багато стандартних Cтруктура даних, реалізованих в мові Java, оперує об'єктами, і, отже, Ви не можете використовувати ці структури для зберігання даних базових типів. Для подібних (і інших) випадків Java надає оболонки типів, що представляють собою класи, які інкапсулюють дані простого типу в об'єкт. Далі перераховані класи оболонки типів.

Значення базового типу инкапсулируется в оболонку в момент конструювання об'єкта. Упаковане таким чином значення можна отримати назад за допомогою виклику одного з методів, визначених в оболонці. Наприклад, всі оболонки числових типів пропонують наступні методи:

Кожен метод повертає значення заданого базового типу. Наприклад, об'єкт типу Long може повернути значення одного з вбудованих числових типів, включаючи short, double або long.

Процес інкапсуляції значення в об'єкт називається упаковкою (boxing). До появи Java 2 версії 5.0 вся упаковка виконувалася програмістом вручну, за допомогою створення екземпляра оболонки з потрібним значенням. У наведеній далі рядку коду значення 100 упаковується вручну в об'єкт типу Integer:

Процес вилучення значення з оболонки типу називається розпакуванням (unboxing). І знову, до появи Java 2 версії 5.0 вся розпакування виконувалася вручну за допомогою виклику методу оболонки для отримання значення з об'єкта.

У наступному рядку коду значення з об'єкта iOb вручну розпаковується в змінну типу int:

В даному випадку метод intValue () повертає значення типу int з об'єкта iOb. Як пояснювалося раніше, є й інші методи, що дозволяють отримати з об'єкта значення іншого числового типу, такого як byte, short, long, double або float. Наприклад, для отримання значення типу long з об'єкта iOb Вам слід викликати метод iOb.longValue (). Таким чином, можна розпакувати значення в змінну простого типу, що відрізняється від типу оболонки.

Починаючи з первинною версією мови Java, для упаковки і розпаковування вручну виконувалася одна і та ж базова процедура, наведена в попередніх прикладах. Хоча такий спосіб упаковки і розпаковування працює, він стомлює і схильний до помилок, так як вимагає від програміста вручну створювати відповідний об'єкт для упаковки значення і при необхідності його розпакування явно задавати змінну відповідного базового типу. На щастя Java 2, v5.0 докорінно модернізує ці найважливіші процедури, вводячи засоби автоупаковкі / розпакування.

Основи автоупаковкі / розпакування

Завдяки автоупаковке зникає необхідність у створенні вручну об'єкта для інкапсуляції значення простого типу. Вам потрібно тільки привласнити це значення вказівником на об'єкт типу-оболонки. Мова Java автоматично створить для вас цей об'єкт. У наступному рядку наведено приклад сучасного способу конструювання об'єкта типу Integer, що зберігає значення 100:

Зверніть увагу на те, що ніякого об'єкта не створюється явно, за допомогою операції new. Мова Java виконає це автоматично.

Всі деталі виконає для вас мову Java.

У лістингу 2.1 приведена коротка програма, яка ввібрала в себе всі наведені раніше фрагменти і демонструє основи механізму автоупаковкі / розпакування,

Лістинг 2.1. Демонстрація застосування автоупаковкі / розпакування

Зверніть увагу ще раз на те, що не потрібно явно створювати об'єкт типу Integer для упаковки значення 100 і немає необхідності викликати метод intValue () для розпакування цього значення.

Автоупаковка і методи

Лістинг 2.2. Автоупаковка / розпакування параметрів методу і повертаються їм значень

Програма лістингу 2.2 відображає наступний очікуваний результат:

У наведеній програмі метод задає параметр типу Integer і повертає результат типу int. У тілі main () методу m () передається значення 100. Оскільки очікує об'єкт типу Integer, що передається значення автоматично упаковується. Далі метод то повертає еквівалент свого аргументу, але простого типу int. Це призводить до автоматичної розпакування в змінну v. Далі в методі main () об'єкту iOb присвоюється це значення типу int, що викликає його автоупаковку. Головна перевага полягає в тому, що всі перетворення виконуються автоматично.

Автоупаковка / розпакування в виразах

Взагалі, автоупаковка / розпакування відбувається завжди, коли потрібно конвертувати в об'єкт або з об'єкта. Це стосується і до виразів. У них числовий об'єкт автоматично розпаковується. Результат виразу повторно упаковується, якщо це необхідно. Розглянемо програму, наведену в лістингу 2.3.

Лістинг 2.3. Автоупаковка / розпакування всередині виразів

Нижче наведено висновок програми, що відображає результати її роботи.

Зверніть особливу увагу на наступний рядок програми з лістингу 2.3:

Вона викликає збільшення на одиницю значення, упакованого в об'єкті iOb. Ця дія виконується наступним чином: об'єкт iOb розпаковується, значення збільшується, і результат повторно упаковується.

Лістинг 2.4. Обробка числових об'єктів різних типів в одному вираженні

Нижче наведено результат роботи програми з лістингу 2.4.

Як бачите, і об'єкт dOb типу Double, і об'єкт iOb типу Integer брали участь у складанні, а результат був повторно упакований і збережений в об'єкті dOb.

Коли обчислюється вираз в операторі switch, розпаковується об'єкт iOb і витягується значення типу int.

Наведені приклади програм показують, що наявність автоупаковкі / розпакування робить використання числових об'єктів в вираженні легким і інтуїтивно зрозумілим. У минулому в цей код довелося б вставляти виклики методів, подібних intValue ().

Автоупаковка / розпакування логічних і символьних значень

Крім оболонок для числових типів мову Java також надає оболонки для даних типів boolean і char. Вони називаються Boolean і Character відповідно. До них також застосовні автоупаковка / розпакування. Розглянемо програму, наведену в лістингу 2.5.

Лістинг 2.5. Автоупаковка / розпакування типів Boolean і Character

Нижче наведено висновок програми з лістингу 2.5, що відображає результати її роботи:

Більш того, тепер об'єкт типу Boolean можна застосовувати для управління будь-якими операторами циклу мови Java. Коли об'єкт типу Boolean використовується як умовний вираз в циклах while, for, do / while, він автоматично розпаковується в еквівалент простого типу boolean. Наприклад, наведений далі фрагмент тепер абсолютно коректний.

Допомога автоупаковкі / розпакування в попередженні помилок

Крім зручності, яке надає механізм автоупаковкі / розпакування, він може допомогти в запобіганні помилок. Розглянемо програму, наведену в лістингу 2.6.

Лістинг 2.6. Помилка, що виникла при розпакуванні вручну

застереження

Тепер, коли в мову Java включені кошти автоупаковкі / розпакування, може з'явитися бажання використовувати тільки числові об'єкти типу Integer або Double, повністю відмовившись від даних простих типів. Наприклад, завдяки наявності автоупаковкі / розпакування тепер можна написати код, подібний наведеному далі.

Приклад поганого використання автоупаковкі / розпакування Double a, b, c;

1. Не пройшло і пів року як згадали що колись Джава 5 з'явилася :)
2.

Незважаючи на виграш в продуктивності, пропонований базовими типами, виникають ситуації, що вимагають обов'язкового об'єктного уявлення. Наприклад, Ви не можете передати в метод змінну базового типу як параметр за посиланням. [Quote]

3.
[Quote] int m (Integer v) <
return v; // auto-unbox to int
>

Допомога автоупаковкі / розпакування в попередженні помилок

---------------
Вибачте за мою українську
Заяць Андрій aka Rebbit
BR