HashMap и int как ключ


104

Я пытаюсь создать HashMap, в котором будут целые числа в качестве ключей и объекты в качестве значений.

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

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

Однако возвращаемая ошибка - Синтаксическая ошибка токена "int", ожидаемые размеры после этого токена - я не понимаю, почему я должен добавить измерение (например, преобразовать int в массив), поскольку мне нужно сохранить только цифру как ключ.

Что я мог сделать?

Заранее спасибо! :)


14
HashMapне обрабатывает примитивы, только объекты.
— Menno

Связанный вопрос SO , но с intценностью, а не с ключом.
— cyroxx

5
IntegerВместо этого используйте .
— Hot Licks

Лучше автоматизировать int в Integer или просто хранить данные в виде String, что более удобно?
— Марчин Эрбель

Ответы:


25

Вы не можете использовать примитив, потому что HashMap использует объект внутри для ключа. Таким образом, вы можете использовать только объект, унаследованный от Object (то есть любой объект).

Это функция put () в HashMap, и, как вы можете видеть, она использует Object для 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
Я знаю, что вы знаете :) Я просто хочу убедиться, что ОП знает / учится. Насколько я знаю, он мог указать имя переменной в параметре типа.
— Адам Гент

1
Небольшая заметка, лучше использовать Android ArrayMapили SimpleArrayMapAndroid для экономии памяти и повышения производительности ( дополнительная информация )
— Ной Хупперт

42

Для всех, кто кодирует Java для устройств Android и оказывается здесь: используйте SparseArrayдля повышения производительности;

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

с этим вы можете использовать int вместо Integer, например;

int newPos = 3;

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

7
Помните, что SparseArray медленнее, чем hashmap, но более эффективно использует память. Так что не используйте его для больших наборов данных.
— TpoM6oH

Как SparseArray используется для повышения производительности, когда он работает медленнее? Какой из них использовать в моей игре для Android
— Snake,

@Snake. SparseArrayЕсли вы выделите кучу вставок для упаковки и распаковки памяти, как в случае с a HashMap, виртуальной машине нужно будет приостановить выполнение для сборки мусора раньше. Это важно, если вы пытаетесь что-то делать часто и быстро.
— Джон

1
Помните , что сложность вставки в SparseArrayэто O (п) ( HashMapимеет O (1) ). Это важно при большом количестве элементов. Вставка в начало такого массива происходит намного медленнее.
— Владимир Петракович

1
@ М.каземАхгары Не совсем так. put()принимает O(n)(не n log n) для вставки в начале, потому что он находит позицию, а затем сдвигает все следующие элементы. delete()сам по себе действительно принимает O(log n), но следующая вставка или повторение элементов после удаления потребует сборки мусора, которая принимает O(n).
— Владимир Петракович


4

Основная причина, по которой HashMap не позволяет использовать примитив в качестве ключей, заключается в том, что HashMap разработан таким образом, что для сравнения ключей он использует метод equals () , и метод может быть вызван только для объекта, а не для примитива.

Таким образом, когда int автоматически преобразуется в Integer, Hashmap может вызывать метод equals () для объекта Integer.

Вот почему вы должны использовать Integer вместо int. Я имею в виду, что hashmap выдает ошибку при вводе int в качестве ключа (не знаю смысла выданной ошибки)

И если вы так думаете, вы можете повысить производительность Map, сделав примитив в качестве ключа, существует библиотека FastUtil, которая содержит реализацию Map с типом int в качестве ключа.

Из-за этого он намного быстрее, чем Hashmap.


1
Нет, основная причина запрета примитивных типов - это стирание типов в Java, которое эффективно превращается Map<Integer, String>во Map<Object, Object>время компиляции. Кстати, есть IdentityHashMap, который использует ==оператор для проверки равенства, который по-прежнему не допускает примитивных типов.
— Yoory N. 05

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 как объект, а не как примитивный тип

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-> object , также рассмотрите возможность использования YourObjectType[]массива или List<YourObjectType>доступа к значениям по индексу, поскольку map по своей природе является ассоциативным массивом с типом int в качестве индекса.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.