Чому Java Collection не можуть безпосередньо зберігати типи примітивів?


123

У колекціях Java зберігаються лише об'єкти, а не примітивні типи; проте ми можемо зберігати класи для обгортки.

Чому це обмеження?


2
Це обмеження не спрацьовує, коли ви маєте справу з примітивами і хочете використовувати Черги для надсилання, а ваші швидкості відправки дуже швидкі. Я зараз займаюся цим питанням, коли автобоксинг займає занадто багато часу.
JPM

Технічно примітивні типи - це об'єкти (однотонні екземпляри таких, щоб бути точними), вони просто не визначаються а class, а не JVM. Оператор int i = 1визначає вказівник на однотонний екземпляр об'єкта, який визначається intв JVM, встановлений на значення, 1визначене десь у JVM. Так, покажчики на Java - це просто абстрагується від вас мовною реалізацією. Примітиви не можна використовувати як дженерики, тому що мова передбачає, що всі загальні типи повинні бути супертиповими Object- отже, чому A<?>компілюється A<Object>в час виконання.
Роберт Е Фрай

1
Примітивні типи @RobertEFry не є об’єктами на Java, тому все, що ви писали про одноосібні екземпляри, і таке, в принципі, помилкове і заплутане. Я пропоную прочитати розділ "Типи, значення та змінні" специфікації мови Java, який визначає, що таке об'єкт: "Об'єкт (§4.3.1) - це динамічно створений екземпляр типу класу або динамічно створений масив. "
typeracer

Відповіді:


99

Це було дизайнерське рішення Java, яке вважають помилковим. Контейнери хочуть, щоб Об'єкти та примітиви не походять від Об'єкту.

Це одне місце, про яке дизайнери .NET дізналися з JVM та реалізували типи значень та загальну інформацію, так що бокс усувається у багатьох випадках. У CLR загальні контейнери можуть зберігати типи значень як частину основної структури контейнера.

Java вирішила додати загальну підтримку на 100% у компіляторі без підтримки JVM. JVM, який є тим, що він є, не підтримує об'єкт "без об'єкта". Java-дженерики дозволяють зробити вигляд, що немає обгортки, але ви все одно платите ціну продуктивності боксу. Це ВАЖЛИВО для певних класів програм.

Бокс - це технічний компроміс, і я вважаю, що це деталізація протікання мови. Автобоксинг є хорошим синтаксичним цукром, але все одно є покаранням за продуктивність. Якщо що, я хотів би, щоб компілятор попередив мене, коли він завантажується автоматично. (Наскільки я знаю, це може бути, я написав цю відповідь у 2010 році).

Хороше пояснення щодо ТА щодо боксу: Чому для деяких мов потрібні бокс та розпакування?

І критика Java-дженериків: Чому деякі стверджують, що реалізація генеричних файлів Java погана?

На захист Java легко дивитися назад і критикувати. JVM витримав випробування часом і багато в чому є хорошим дизайном.


6
Не помилка, ретельно підібраний компроміс, який, на мою думку, справді слугував Java.
DJClayworth

13
Було достатньо помилки, що .NET дізнався з цього і реалізував автобоксинг з самого початку, а також загальну інформацію на рівні VM без боксу накладних витрат. Власна спроба Java виправити було лише рішенням рівня синтаксису, яке все ще страждає від хіта на продуктивність автобоксингу проти взагалі ніякого боксу. Реалізація Java показала низьку ефективність із великими структурами даних.
codenheim

2
@mrjoltcola: IMHO, автоматичне завантаження за замовчуванням - помилка, але повинен бути спосіб тегування змінних та параметрів, які повинні автоматично встановлювати задані їм значення. Навіть зараз я думаю, що має бути доданий засіб для визначення того, що певні змінні чи параметри не повинні приймати нещодавно автобоксифіковані значення [наприклад, це повинно бути законним для передачі Object.ReferenceEqualsпосилань типу, Objectякі ідентифікують цілі числа, але це не повинно бути законним передавати ціле значення]. Автоматичне розпакування Java - це IMHO просто неприємно.
supercat

18

Полегшує реалізацію. Оскільки примітивні Java не вважаються Об'єктами, вам потрібно створити окремий клас колекції для кожного з цих примітивів (коду шаблону не можна ділити).

Ви можете це зробити, звичайно, просто побачити GNU Trove , Apache Commons Primitive або HPPC .

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


11

Це поєднання двох фактів:

  • Примітивні типи Java не є типовими типами (наприклад, ан intне є Object)
  • Java виконує дженерики, використовуючи стирання типів посилань (наприклад, List<?>це справді List<Object>під час виконання)

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

Чи можна було цього уникнути? Можливо,

  • Якщо ан intє Object, то типи вікон взагалі не потрібні.
  • Якщо дженеріки не виконуються за допомогою стирання типу, то примітивісти можуть бути використані для параметрів типу.

8

Існує концепція автобоксу та авторозпакування. Якщо ви спробуєте зберегти intв List<Integer>компіляторі Java, він автоматично перетворить його на Integer.


1
Автобоксинг був представлений у Java 1.5 разом із Generics.
Джеремі

1
Але це час компіляції; синтаксичний цукор без користі для продуктивності. Автоматичні ящики компілятора Java, отже, штрафні показники порівняно з реалізацією VM, як-от .NET, які генеричні засоби не включають бокс.
codenheim

1
@mrjoltcola: Що ти думаєш? Я просто ділився фактами, не аргументуючи.
Джеремі

3
Моє значення - важливо вказати на різницю між синтаксисом та продуктивністю. Я також вважаю свої коментарі поділом фактів, а не аргументом. Дякую.
codenheim

2

Це насправді не обмеження?

Подумайте, чи хотіли ви створити колекцію, яка зберігала примітивні значення. Як би ви написали колекцію, яка може зберігати або int, або float, або char? Швидше за все, ви отримаєте декілька колекцій, тож вам знадобиться список списку та список значень тощо

Користуючись об'єктно-орієнтованою природою Java, коли ви пишете клас колекції, він може зберігати будь-який об’єкт, тому вам потрібен лише один клас колекції. Ця ідея, поліморфізм, є дуже потужною і значно спрощує дизайн бібліотек.


7
"Як би ви написали колекцію, яка може зберігати або int, або float, або char?" - З правильно реалізованими дженериками / шаблонами, як інші мови, які не платять штраф за вигляд, що все є об'єктом.
codenheim

Я майже ніколи за шість років Java не хотів зберігати колекцію примітивів. Навіть у кількох випадках, коли я, можливо, хотів би, щоб додаткові витрати часу та простору на використання опорних об'єктів були незначними. Зокрема, я вважаю, що багато людей думають, що хочуть Map <int, T>, забуваючи, що масив дуже добре виконає цю хитрість.
DJClayworth

2
@DJClayworth Це добре працює лише в тому випадку, якщо ключові значення є нерідкими. Звичайно, ви можете використовувати допоміжний масив для відстеження ключів, але у цього є свої проблеми: відносно ефективний доступ вимагає збереження обох масивів відсортованих на основі ключового порядку, щоб дозволити двійковий пошук, що, в свою чергу, зробить вставку та видалення неефективна, якщо вставка / видалення не буде малювати таким чином, що вставлені елементи, ймовірно, закінчуються там, де раніше був видалений елемент та / або деякі буфери перемежовуються в масивах тощо. Є ресурси, але було б непогано мати Сама Java.
JAB

@JAB Насправді це добре працює, якщо клавіші рідкі, йому просто потрібно більше пам'яті, ніж якщо вони не рідкі. І якщо вони клавіші рідкі, це означає, що їх не так багато, і використання Integer як ключа працює добре. Використовувати будь-який підхід потребує найменшої пам’яті. Або як би ви не відчували себе, якщо вам все одно.
DJClayworth

0

Я думаю, що ми можемо побачити прогрес у цьому просторі в JDK, можливо, в Java 10 на основі цього JEP - http://openjdk.java.net/jeps/218 .

Якщо ви сьогодні хочете уникнути боксерських примітивів у колекціях, є кілька сторонніх альтернатив. Окрім раніше згаданих сторонніх опцій є також Eclipse Collections , FastUtil та Koloboke .

Порівняння примітивних карт також було опубліковано деякий час тому під заголовком: Огляд великих HashMap: JDK, FastUtil, Goldman Sachs, HPPC, Koloboke, Trove . Бібліотека колекцій GS Collections (Goldman Sachs) була перенесена до фонду Eclipse Foundation і тепер є Eclipse Collections.


0

Основна причина - стратегія дизайну java. ++ 1) колекції вимагають об'єктів для маніпулювання, а примітиви не виводяться з об'єкта, тому це може бути іншою причиною. 2) Примітивні типи даних Java не є еталонним типом для напр. int не є об'єктом.

Подолати:-

у нас є концепція автоматичного боксу та авторозпакування. тому якщо ви намагаєтесь зберігати примітивні типи даних, компілятор автоматично перетворить це в об’єкт цього примітивного класу даних.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.