У цій статті ми розглянемо таку функцію Java як автоупаковка/распаковка . Автоупаковка та розпакування це функція перетворення примітивних типів в об'єктні та навпаки. Весь процес виконується автоматично середовищем виконання Java (JRE). Але слід бути обережним під час реалізації цієї функції, т.к. Вона може впливати на продуктивність вашої програми.
Таблиця 1: Примітивні типи та еквівалентні їм класи оболонки з операторами порівняння Автоупаковка та розпакування можуть використовуватись з операторами порівняння. Наступний фрагмент коду ілюструє, як це відбувається: Лістинг 3: Приклад коду, що показує автоупаковку та розпакування з оператором порівняння
Вступ
У версіях нижче JDK 1.5 було легко перетворювати примітивні типи даних, такі якint
, char
, float
, double
в їх класи оболонки Integer, Character, Float, Double. Починаючи з версії JDK 5 ця функція, перетворення примітивних типів на еквівалентні об'єкти, реалізована автоматично. Ця властивість відома як Автоупаковка (Autoboxing). Зворотний процес відповідно – Розпакування (Unboxing) тобто. процес перетворення об'єктів у відповідні їм примітивні типи. Приклад коду для автоупаковки та розпакування представлений нижче: Автоупаковка
Integer integer = 9;
Розпакування
int in = 0;
in = new Integer(9);
Коли використовується автоупаковка та розпакування? Автоупаковка застосовується компілятором Java за таких умов:
- Коли значення примітивного типу передається в метод як параметр методу, який очікує на об'єкт відповідного класу-оболонки.
- Коли значення примітивного типу надається змінної, відповідного класу оболонки.
public int sumEvenNumbers(List<Integer> intList ) {
int sum = 0;
for (Integer i: intList )
if ( i % 2 == 0 )
sum += i;
return sum;
}
До версії jdk 1.5 наведений вище код викликав би помилку компіляції, оскільки оператор отримання залишку % і унарний плюс += не могли застосовуватися до класу-оболонки. Але в jdk 1.5 і вище цей код компілюється без помилок, перетворюючи Integer на int
. Розпакування застосовується компілятором Java за таких умов:
- Коли об'єкт передається як параметр методу, який очікує відповідний примітивний тип.
- Коли об'єкт надається змінної відповідного примітивного типу.
import java.util.ArrayList;
import java.util.List;
public class UnboxingCheck {
public static void main(String[] args) {
Integer in = new Integer(-8);
// 1. Распаковка через вызов метода
int absVal = absoluteValue(in);
System.out.println("absolute value of " + in + " = " + absVal);
List<Double> doubleList = new ArrayList<Double>();
// Автоупаковка через вызов метода
doubleList.add(3.1416);
// 2. Распаковка через присвоение
double phi = doubleList.get(0);
System.out.println("phi = " + phi);
}
public static int absoluteValue(int i) {
return (i < 0) ? -i : i;
}
}
Автоупаковка та розпакування дозволяють розробнику писати код, який легко читається та зрозумілий. Наступна таблиця показує примітивні типи даних та їх відповідні об'єкти оболонки.
Примітивні типи | Класи оболонки |
---|---|
boolean | Boolean |
byte | Byte |
char | Character |
float | Float |
int | Integer |
long | Long |
short | Short |
public class BoxedComparator {
public static void main(String[] args) {
Integer in = new Integer(25);
if (in < 35)
System.out.println("Value of int = " + in);
}
}
Автоупаковка та розпакування при перевантаженні методу Автоупаковка та розпакування виконується при перевантаженні методу на підставі наступних правил:
- Розширення "перемагає" упаковку в ситуації, коли стає вибір між розширенням і упаковкою, розширення краще.
public class WideBoxed {
public class WideBoxed {
static void methodWide(int i) {
System.out.println("int");
}
static void methodWide( Integer i ) {
System.out.println("Integer");
}
public static void main(String[] args) {
short shVal = 25;
methodWide(shVal);
}
}
}
Виведення програми - типint
- Розширення перемагає змінну кількість аргументів у ситуації, коли стає вибір між розширенням і змінною кількістю аргументів, розширення краще.
public class WideVarArgs {
static void methodWideVar(int i1, int i2) {
System.out.println("int int");
}
static void methodWideVar(Integer... i) {
System.out.println("Integers");
}
public static void main( String[] args) {
short shVal1 = 25;
short shVal2 = 35;
methodWideVar( shVal1, shVal2);
}
}
- Упаковка перемагає змінну кількість аргументів у ситуації, коли стає вибір між упаковкою та змінною кількістю аргументів, упаковка краща.
public class BoxVarargs {
static void methodBoxVar(Integer in) {
System.out.println("Integer");
}
static void methodBoxVar(Integer... i) {
System.out.println("Integers");
}
public static void main(String[] args) {
int intVal1 = 25;
methodBoxVar(intVal1);
}
}
Ви повинні пам'ятати про наступні речі, використовуючи Автопакування: Як ми знаємо, будь-яка хороша функція має недолік. Автоупаковка не є винятком щодо цього. Деякі важливі зауваження, які повинен враховувати розробник під час використання цієї функції:
- Порівнюючи об'єкти оператором
==
може виникнути плутанина, оскільки він може застосовуватися до примітивних типів і об'єктів. Коли цей оператор застосовується до об'єктів, він фактично порівнює посилання на об'єкти, а не самі об'єкти.
public class Comparator {
public static void main(String[] args) {
Integer istInt = new Integer(1);
Integer secondInt = new Integer(1);
if (istInt == secondInt) {
System.out.println("both one are equal");
} else {
System.out.println("Both one are not equal");
}
}
}
- Змішування об'єктів та примітивних типів з оператором рівності та відносини. Якщо ми порівнюємо примітивний тип з об'єктом, то відбувається розпаковування об'єкта, який може залишити
NullPointerException
об'єктnull
. - Кешування об'єктів. Метод
valueOf()
створює контейнер примітивних об'єктів, які він кешує. Оскільки значення кешуються в діапазоні від -128 до 127 включно, ці об'єкти, що кешуються, можуть поводитися по-різному. - Погіршення продуктивності. Автоупаковка або розпакування погіршують продуктивність програми, оскільки це створює небажаний об'єкт, через який збирачеві сміття доводиться працювати частіше.
public int sumEvenNumbers(List intList) {
int sum = 0;
for (Integer i : intList) {
if (i % 2 == 0) {
sum += i;
}
}
return sum;
}
У цій ділянці коду sum +=i
буде розширено на sum = sum + i
. Починаючи з оператора +
JVM запускає розпакування, оскільки оператор +
не може застосовуватися до об'єкта Integer. А потім результат автоупаковується назад. До версії JDK 1.5 типи даних int
та Integer відрізнялися. У разі навантаження методу ці два типи використовувалися без проблем. З появою автоматичного пакування/розпакування це стало складніше. Прикладом цього є перевантажений remove()
метод ArrayList
. Клас ArrayList
має два методи видалення - remove(index)
і remove(object)
. У цьому випадку перевантаження методів не відбудеться і відповідний метод буде викликатись з відповідними параметрами.
Висновок
Автопакування є механізмом для прихованого перетворення примітивних типів даних у відповідні класи-оболонки (об'єкти). Компілятор використовує метод,valueOf()
щоб перетворити примітивні типи на об'єкти, а методи IntValue()
, doubleValue()
і т.д., щоб отримати примітивні типи об'єкта. Автоупаковка перетворює логічний тип boolean
у Boolean, byte
Byte, char
Character, float
Float, int
Integer, long
Long, short
Short. Розпакування відбувається у зворотному напрямку. Оригінал статті
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ