Для повного розуміння головної причини цього потрібен певний контекст.
Примітиви проти класів
Примітивні змінні в 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
це незручно, бувають випадки, коли мова робить це автоматично - це називається автобокс .