HashMap та int як ключові


104

Я намагаюся створити HashMap, який буде мати цілі числа як ключі, так і об'єкти як значення.

Мій синтаксис:

HashMap<int, myObject> myMap = new HashMap<int, myObject>();

Однак повертається помилка - помилка синтаксису в токені "int", розміри, очікувані після цього маркера, - я не розумію, чому я повинен додати параметр (тобто: введення int в масив), оскільки мені потрібно зберігати лише цифру як ключовий.

Що я міг зробити?

Спасибі заздалегідь! :)


14
HashMapне обробляє примітиви, а лише предмети.
Менно

Питання , пов'язані ТА , але intце значення, а не ключове.
cyroxx

5
Використовуйте Integerзамість цього.
Гарячі лизання

Чи краще автобокс int до Integer або просто зберігати дані як String, що зручніше?
Марцін Ербель

Відповіді:


25

Ви не можете використовувати примітив, оскільки HashMap використовує об'єкт внутрішньо для ключа. Отже, ви можете використовувати лише об'єкт, який успадковується від Object (тобто будь-який об'єкт).

Це функція put () у HashMap, і як ви бачите, вона використовує Object for K:

public V put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key);
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

Вираз "k = e.key" повинен дати зрозуміти.

Я пропоную використовувати обгортку на зразок Integer та autoboxing.


137

Використовуйте Integerзамість цього.

HashMap<Integer, MyObject> myMap = new HashMap<Integer, MyObject>();

Java автоматично автоматично завантажує ваші intпримітивні значення в Integerоб'єкти.

Детальніше про автобоксинг читайте з документації Oracle Java.


10
Він також не повинен називати класmyObject
Адам Гент

@AdamGent Правильно. Усі назви класів повинні починатися з великих літер, я виправив рекомендований код.
gaborsch

3
Я знаю, що ви знаєте :) Я просто хочу переконатися, що ОП знає / вчиться. Я знаю, що він міг би вводити ім'я змінної в параметр type.
Адам Гент

1
Лише невелика примітка, краще використовувати Android ArrayMapабо SimpleArrayMapAndroid для збереження пам’яті та підвищення продуктивності ( Детальніше )
Noah Huppert

42

Для всіх, хто кодує Java для пристроїв Android і закінчується тут: використовувати SparseArrayдля кращої продуктивності;

private final SparseArray<myObject> myMap = new SparseArray<myObject>();

за допомогою цього ви можете використовувати int замість Integer like;

int newPos = 3;

myMap.put(newPos, newObject);
myMap.get(newPos);

7
Пам'ятайте, що SparseArray повільніше, ніж хешмап, але ефективніше пам'яті. Тому не використовуйте його для великих наборів даних.
TpoM6oH

Як SparseArray використовується для кращої продуктивності, але вона повільніше? Яку використовувати в моїй грі на андроїд
Snake

@Snake SparseArrayЯкщо ви виділите купу входів для боксу та розпакування пам’яті, як у випадку із a HashMap, vm потрібно швидше призупинити виконання для збирання сміття. Це важливо, якщо ви намагаєтесь робити щось часто і швидко.
Джон

1
Пам'ятайте , що складність вставки в SparseArrayце O (п) ( HashMapмає O (1) ). Важливо, коли кількість елементів велика. Введення в початок такого масиву відбувається набагато повільніше.
Володимир Петракович

1
@ M.kazemAkhgary Не зовсім. put()бере O(n)(не n log n) для вставки на початку, тому що знаходить положення, а потім зміщує всі наступні елементи. delete()Сам по собі дійсно займає O(log n), але наступне вставлення або повторення через елементи після видалення потребуватиме сміття, яке займе O(n).
Володимир Петракович


4

Основна причина того, що HashMap не дозволяє примітивувати як ключі, полягає в тому, що HashMap розроблений таким чином, що для порівняння ключів використовується метод equals () , а метод можна викликати лише на об'єкті, а не на примітиві.

Таким чином, коли int автоматично завантажується в Integer, Hashmap може викликати метод equals () на об'єкт Integer.

Ось чому слід використовувати Integer замість int. Я маю на увазі, що хешмап видає помилку під час введення ключа як ключа (не знаю значення помилки, яку викидають)

І якщо ви вважаєте це, ви можете зробити швидкість роботи Карти швидше, зробивши примітив як ключ, є бібліотека під назвою FastUtil, яка містить реалізацію Map з типом int як ключ.

Через це він набагато швидше, ніж Hashmap


1
Ні, головна причина заборони примітивних типів - стирання типу на Java, яке фактично перетворюється Map<Integer, String>під Map<Object, Object>час компіляції. До речі, існує IdentityHashMap, який використовує ==оператор для перевірки рівності, який все ще не дозволяє примітивні типи.
Yoory N.

3

HashMap не дозволяє примітивні типи даних в якості аргументів. Він може приймати об'єкти лише так

HashMap<int, myObject> myMap = new HashMap<int, myObject>();

не вийде.

Ви повинні змінити декларацію на

HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();

тому навіть коли ви робите наступне

myMap.put(2,myObject);

Примітивний тип даних автоматично завантажується в об'єкт Integer.

8 (int) === boxing ===> 8 (Integer)

Детальніше про автобоксинг ви можете прочитати тут http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html



1

використовувати int як Object не як примітивний тип

HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();

Я написав HashMap <Integer, MyObject> myMap = new HashMap <Integer, MyObject> (); але показ моєї проблеми з> і <, щоб відобразити гарну відповідь
franki3xe

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

0

Будь ласка, використовуйте HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();


0

Я не розумію, чому я повинен додати параметр (тобто: введення int в масив), оскільки мені потрібно лише зберігати цифру як ключ.

Масив також є Об'єктом, тому HashMap<int[], MyObject>це дійсна конструкція, яка використовує масиви int як ключі.

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


1
Будьте уважні з цим, хеш-значення масиву не пов'язане з його вмістом, тому два масиви з однаковим вмістом можуть хешувати інше значення, що робить його дуже поганим ключем.
john16384

0

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

import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap;

public class Check {
    public static void main(String[] args) {
        IntObjectHashMap map = new IntObjectHashMap();

        map.put(5,"It works");
        map.put(6,"without");
        map.put(7,"boxing!");

        System.out.println(map.get(5));
        System.out.println(map.get(6));
        System.out.println(map.get(7));
    }
}

У цьому прикладі вище IntObjectHashMap .

Оскільки вам потрібно int-> об'єктне відображення, також врахуйте використання значень YourObjectType[]масиву або List<YourObjectType>доступу за індексом, оскільки карта за своєю природою є асоціативним масивом з типом int як індексом.

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