JavaRush /Java блог /Random UA /Обгортки, розпакування та запакування

Обгортки, розпакування та запакування

Стаття з групи Random UA
Вітання! Ти вже непогано знайомий із примітивними типами, і чимало з ними попрацював. Обгортки, розпакування та запаковка - 1У примітивів у програмуванні, і Java зокрема, є безліч переваг: вони займають мало пам'яті, за рахунок чого підвищується ефективність роботи програми, і чітко розділені по діапазонах значень. Однак у процесі вивчення Java ми неодноразово, немов мантру, повторювали — “ в Java все є об'єктом ”. Адже примітиви — пряме спростування цих слів. Об'єктами вони є. Виходить, принцип "все є об'єктом" є хибним? Насправді ні. У Java у кожного примітивного типу є свій брат-близнюк - клас-обгортка ( Wrapper). Що таке обгортка? Обгортка - це спеціальний клас, який зберігає в собі значення примітиву. Але оскільки це саме клас, він може створювати свої екземпляри. Вони зберігатимуть усередині потрібні значення примітивів, у своїй будуть справжніми об'єктами. Назви класів-оберток дуже схожі на назви відповідних примітивів, або повністю з ними збігаються. Тож запам'ятати їх буде дуже легко.
Wrapper Classes for Primitive Data Types
Primitive Data Types Wrapper Classes
int Integer
short Short
long Long
byte Byte
float Float
double Double
char Character
boolean Boolean
Об'єкти класів обгорток створюються так само, як і будь-які інші:
public static void main(String[] args) {

   Integer i = new Integer(682);

   Double d = new Double(2.33);

   Boolean b = new Boolean(false);
}
Класи-обертки дозволяють нівелювати недоліки, які є у примітивних типів. Найочевидніший із них — примітиви не мають методів . Наприклад, у них немає методу toString(), тому ти не зможеш, наприклад, перетворити число intна рядок. А ось із класом-обгорткою Integer— запитто.
public static void main(String[] args) {

   Integer i = new Integer(432);

   String s = i.toString();
}
Виникнуть складнощі і зі зворотним перетворенням. Припустимо, у нас є рядок, про який ми точно знаємо, що він містить число. Тим не менш, у випадку з примітивним типом intми ніяк не зможемо це число з рядка дістати і перетворити, власне, на число. Але завдяки класам-обгорткам така можливість у нас з'явилася.
public static void main(String[] args) {

   String s = "1166628";

   Integer i = Integer.parseInt(s);

   System.out.println(i);
}
Висновок: 1166628 Ми успішно отримали число з рядка і привласнабо його в змінну-посилання Integer i. До речі, щодо посилань. Ти вже знаєш, що параметри передаються в методи по-різному: примітиви за значенням, а об'єкти за посиланням. Ти можеш використовувати це знання при створенні своїх методів: якщо твій метод працює, наприклад, з дробовими числами, але тобі потрібна логіка саме передачі за посиланням, ти можеш передати метод параметри Double/Floatзамість double/float. Крім того, крім методів у класах-обгортках є дуже зручні для використання статичні поля. Наприклад, уяви, що перед тобою зараз стоїть завдання: вивести в консоль максимально можливе число int, а потім мінімально можливе. Завдання начебто елементарне, а все одно — без гугла навряд чи впораєшся. А класи-обгортки легко дозволяють вирішувати такі “побутові завдання”:
public class Main {
   public static void main(String[] args) {

       System.out.println(Integer.MAX_VALUE);
       System.out.println(Integer.MIN_VALUE);
   }
}
Такі поля дозволяють не відволікатися від більш серйозних завдань. Не кажучи вже про те, що в процесі друку числа 2147483647 (це якраз MAX_VALUE) не дивно і опечататися:) Крім того, в одній з минулих лекцій ми вже звертали увагу на те, що об'єкти класів- обгорток є незмінними (Immutable) .
public static void main(String[] args) {

   Integer a = new Integer(0);
   Integer b = new Integer(0);

   b = a;
   a = 1;
   System.out.println(b);
}
Висновок: 0 Об'єкт, на який спочатку вказувало посилання а, не змінив свій стан, інакше значення bтеж змінилося б. Як і у випадку зіStringзамість зміни стану об'єкта-обгортки в пам'яті створюється абсолютно новий об'єкт. Чому ж творці Java, зрештою, вирішабо залишити у мові примітивні типи? Якщо все має бути об'єктом, і ми вже маємо класи-обгортки, якими можна висловити все, що виражають примітиви, чому взагалі не залишити в мові тільки їх, а примітиви видалити? Відповідь проста - продуктивність. Примітивні типи тому і називають примітивними, тому що вони позбавлені багатьох "важкоатлетних" особливостей об'єктів. Так, об'єкт має багато зручних методів, але ж вони не завжди тобі потрібні. Іноді тобі потрібно просто число 33, чи 2,62, чи значення true/ false. У ситуаціях, коли всі переваги об'єктів не мають значення і не потрібні для роботи програми, примітиви впораються із завданням набагато краще.

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

Однією з особливостей примітивів та їх класів-обгорток у Java є автоупаковка/автораспаковка (Autoboxing/Autounboxing) Обгортки, розпакування та запаковка - 2 Давай розберемося з цим поняттям. Як ми з тобою вже дізналися раніше, Java - об'єктно-орієнтована мова. Це означає, що всі програми, написані Java, складаються з об'єктів. Примітиви є об'єктами. Але при цьому змінної класу-обгортки можна надавати значення примітивного типу. Цей процес називається автоупаковкою ( autoboxing ). Так само змінної примітивного типу можна надавати об'єкт класу-обгортки. Цей процес називається авторапакуванням (autounboxing) . Наприклад:
public class Main {
   public static void main(String[] args) {
       int x = 7;
       Integer y = 111;
       x = y; // авторопакування
       y = x * 123; // Автоупаковка
   }
}
У рядку 5 ми присвоюємо примітиву x значення y, який є об'єктом класу-обгортки Integer. Як бачиш, ніяких додаткових дій для цього не потрібно: компілятор знає що intі Integer, по суті, те саме . Це і є авторопакування. Також відбувається і автоупаковка в рядку 6: об'єкту y легко присвоюється значення примітивів (х*123). Це приклад автоупаковки. Саме тому додається слово "авто": для присвоєння посилань-примітивів об'єктам їх класів-оберток (і навпаки) не потрібно нічого робити, все відбувається автоматично . Зручно, правда? :) Ще одна дуже велика зручність автоупаковки/автораспаковки проявляється в роботі методів. Справа в тому, що параметри методів теж підлягають автоупаковці та автоупаковці. І, наприклад, якщо один із них приймає на вхід два об'єкти Integer— ми легко можемо передати туди звичайні примітиви int!
public class Main {
   public static void main(String[] args) {

       printNumber(7);//Звичайний int, навіть без змінної
   }

   public static void printNumber(Integer i) {
       System.out.println("Ви ввели число" + i);
   }
}
Висновок: Ви ввели число 7 Так само працює і навпаки:
public class Main {
   public static void main(String[] args) {

       printNumber(new Integer(632));
   }

   public static void printNumber(int i) {
       System.out.println("Ви ввели число" + i);
   }
}
Важливий момент, про який потрібно пам'ятати: автоупаковка та розпакування не працюють для масивів !
public class Main {
   public static void main(String[] args) {

       int[] i = {1,2,3,4,5};

       printArray(i);//помилка, не компілюється!
   }

   public static void printArray(Integer[] arr) {
       System.out.println(Arrays.toString(arr));
   }
}
Спроба передати масив примітивів метод, який приймає на вхід масив об'єктів, викличе помилку компіляції. Насамкінець, ще раз коротко порівняємо примітиви та обгортки .
  • мають перевагу у продуктивності
Обгортки:
  • Дозволяють не порушувати принцип “все є об'єктом”, завдяки чому цифри, символи та булеві значення true/false не випадають із цієї концепції
  • Розширюють можливості роботи з цими значеннями, надаючи зручні методи та поля
  • Необхідно, коли якийсь метод може працювати виключно з об'єктами
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ