JavaRush /Java блог /Random UA /Автоупаковка та розпакування в Java
DSergey_Kh
12 рівень

Автоупаковка та розпакування в Java

Стаття з групи Random UA
У цій статті ми розглянемо таку функцію Java як автоупаковка/распаковка . Автоупаковка та розпакування це функція перетворення примітивних типів в об'єктні та навпаки. Автоупаковка та розпакування в Java - 1Весь процес виконується автоматично середовищем виконання Java (JRE). Але слід бути обережним під час реалізації цієї функції, т.к. Вона може впливати на продуктивність вашої програми.

Вступ

У версіях нижче 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 за таких умов:
  • Коли значення примітивного типу передається в метод як параметр методу, який очікує на об'єкт відповідного класу-оболонки.
  • Коли значення примітивного типу надається змінної, відповідного класу оболонки.
Розглянемо наступний приклад: Лістинг 1: Простий код, що показує автоупаковку
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 за таких умов:
  • Коли об'єкт передається як параметр методу, який очікує відповідний примітивний тип.
  • Коли об'єкт надається змінної відповідного примітивного типу.
Розглянемо наступний приклад: Лістинг 2: Простий код, що показує розпакування
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
Таблиця 1: Примітивні типи та еквівалентні їм класи оболонки з операторами порівняння Автоупаковка та розпакування можуть використовуватись з операторами порівняння. Наступний фрагмент коду ілюструє, як це відбувається: Лістинг 3: Приклад коду, що показує автоупаковку та розпакування з оператором порівняння
public class BoxedComparator {
  public static void main(String[] args) {
      Integer in = new Integer(25);
      if (in < 35)
          System.out.println("Value of int = " + in);
  }
}
Автоупаковка та розпакування при перевантаженні методу Автоупаковка та розпакування виконується при перевантаженні методу на підставі наступних правил:
  • Розширення "перемагає" упаковку в ситуації, коли стає вибір між розширенням і упаковкою, розширення краще.
Лістинг 4: Приклад коду, що показує перевагу навантаження
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
  • Розширення перемагає змінну кількість аргументів у ситуації, коли стає вибір між розширенням і змінною кількістю аргументів, розширення краще.
Лістинг 5: Приклад коду, що показує перевагу навантаження
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);
   }
  }
  • Упаковка перемагає змінну кількість аргументів у ситуації, коли стає вибір між упаковкою та змінною кількістю аргументів, упаковка краща.
Лістинг 6: Приклад коду, що показує перевагу навантаження
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);
    }
}
Ви повинні пам'ятати про наступні речі, використовуючи Автопакування: Як ми знаємо, будь-яка хороша функція має недолік. Автоупаковка не є винятком щодо цього. Деякі важливі зауваження, які повинен враховувати розробник під час використання цієї функції:
  • Порівнюючи об'єкти оператором ==може виникнути плутанина, оскільки він може застосовуватися до примітивних типів і об'єктів. Коли цей оператор застосовується до об'єктів, він фактично порівнює посилання на об'єкти, а не самі об'єкти.
Лістинг 7: приклад коду, що показує порівняння.
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 включно, ці об'єкти, що кешуються, можуть поводитися по-різному.
  • Погіршення продуктивності. Автоупаковка або розпакування погіршують продуктивність програми, оскільки це створює небажаний об'єкт, через який збирачеві сміття доводиться працювати частіше.
Недоліки Автопакування Хоча Автопакування має ряд переваг, вона має такі недоліки: Лістинг 8: Приклад коду, що показує проблему продуктивності.
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, byteByte, charCharacter, floatFloat, intInteger, longLong, shortShort. Розпакування відбувається у зворотному напрямку. Оригінал статті
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ