HashMap i int jako klucz

104

Próbuję zbudować HashMap, który będzie miał liczbę całkowitą jako klucze i obiekty jako wartości.

Moja składnia to:

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

Jednak zwrócony błąd to - Błąd składni na tokenie „int”, Wymiary oczekiwane po tym tokenie - Nie rozumiem, dlaczego powinienem dodać wymiar (tj. Zrobić int do tablicy), ponieważ potrzebuję tylko przechowywać cyfrę jako klucz.

Co mógłbym zrobić?

Z góry dziękuję! :)

MrD
źródło
14
HashMapnie obsługuje prymitywów, tylko obiekty.
Menno
Powiązane pytanie SO , ale z intwartością, a nie kluczem.
cyroxx
5
Użyj Integerzamiast tego.
Hot Licks
Czy lepiej jest autobox int do Integer, czy po prostu przechowywać dane jako String, co jest wygodniejsze?
Marcin Erbel,

Odpowiedzi:

25

Nie możesz użyć prymitywu, ponieważ HashMap używa obiektu wewnętrznie dla klucza. Możesz więc używać tylko obiektu, który dziedziczy po Object (czyli dowolnego obiektu).

To jest funkcja put () w HashMap i jak widać, używa Object dla 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;
}

Wyrażenie „k = e.key” powinno to wyjaśnić.

Proponuję użyć wrappera takiego jak Integer i autoboxing.

user1883212
źródło
137

Użyj Integerzamiast tego.

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

Java automatycznie dokona autoboxu intprymitywnych wartości do Integerobiektów.

Przeczytaj więcej o autoboxingu z dokumentacji Oracle Java.

gaborsch
źródło
10
Nie powinien też nazywać klasymyObject
Adam Gent
@AdamGent Poprawne. Wszystkie nazwy klas powinny zaczynać się od wielkich liter, poprawiłem zalecany kod.
gaborsch
3
Wiem, że wiesz :) Chcę się tylko upewnić, że OP wie / się uczy. Z tego co wiem, mógł wstawić nazwę zmiennej do parametru typu.
Adam Gent,
1
Krótka krótka uwaga, lepiej jest używać ArrayMaplub SimpleArrayMapna Androidzie, aby zaoszczędzić pamięć i zwiększyć wydajność ( Więcej informacji )
Noah Huppert
42

Dla każdego, kto koduje Javę dla urządzeń z Androidem i kończy tutaj: używaj SparseArraydla lepszej wydajności;

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

dzięki temu możesz użyć int zamiast Integer jak;

int newPos = 3;

myMap.put(newPos, newObject);
myMap.get(newPos);
Stepoid
źródło
7
Pamiętaj, że SparseArray jest wolniejszy niż hashmap, ale wydajniejszy pod względem pamięci. Więc nie używaj go na dużych zestawach danych.
TpoM6oH
W jaki sposób używa się SparseArray, aby uzyskać lepszą wydajność, gdy jest wolniejszy? Którego użyć w mojej grze na Androida
Snake
@Snake SparseArrayJeśli przydzielisz dużo pamięci do pakowania i rozpakowywania int, tak jak w przypadku a HashMap, maszyna wirtualna będzie musiała wstrzymać wykonywanie wcześniej w celu czyszczenia pamięci . Jest to ważne, jeśli próbujesz zrobić coś często i szybko.
Jon
1
Pamiętaj, że złożoność wstawiania do SparseArraywynosi O (n) ( HashMapma O (1) ). Jest to ważne, gdy liczba elementów jest duża. Wstawianie na początek takiej tablicy jest znacznie wolniejsze.
Vladimir Petrakovich
1
@ M.kazemAkhgary Niezupełnie. put()przyjmuje O(n)(nie n log n) do wstawienia na początku, ponieważ znajduje pozycję, a następnie przesuwa wszystkie kolejne elementy. delete()faktycznie trwa O(log n), ale następne wstawienie lub iteracja przez elementy po usunięciu będzie wymagało czyszczenia pamięci O(n).
Vladimir Petrakovich
4

Głównym powodem, dla którego HashMap nie dopuszcza prymitywów jako kluczy, jest to, że HashMap jest zaprojektowany w taki sposób, że do porównywania kluczy wykorzystuje metodę equals () , a metodę można wywołać tylko na obiekcie, a nie na prymitywie.

Zatem gdy int jest automatycznie przypisywane do liczby całkowitej, Hashmap może wywołać metodę equals () na obiekcie Integer.

Dlatego powinieneś używać Integer zamiast int. Chodzi mi o to, że hashmap zgłasza błąd podczas umieszczania int jako klucza (nie znam znaczenia wyrzucanego błędu)

A jeśli tak myślisz, możesz zwiększyć wydajność Map, tworząc prymityw jako klucz, istnieje biblioteka o nazwie FastUtil, która zawiera implementację Map z typem int jako kluczem.

Z tego powodu jest znacznie szybszy niż Hashmap

Ojcze Mathew
źródło
1
Nie, głównym powodem niedozwolenia typów pierwotnych jest wymazywanie typów w Javie, które skutecznie zmienia się Map<Integer, String>w Map<Object, Object>podczas kompilacji. BTW, istnieje IdentityHashMap, który używa ==operatora do sprawdzania równości, który nadal nie zezwala na typy pierwotne.
Yoory N.
3

HashMap nie zezwala na prymitywne typy danych jako argumenty. Może przyjmować tylko obiekty tzw

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

nie będzie działać.

Musisz zmienić deklarację na

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

więc nawet jeśli wykonasz poniższe czynności

myMap.put(2,myObject);

Prymitywny typ danych jest automatycznie przypisywany do obiektu typu Integer.

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

Możesz przeczytać więcej na temat autoboxing tutaj http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

Lakshmi
źródło
3

Jeśli kodujesz w systemie Android, istnieje SparseArray , mapujący liczbę całkowitą na obiekt.

alvinsj
źródło
1

użyj int jako Object nie jako typu pierwotnego

HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();
franki3xe
źródło
Napisałem HashMap <Integer, MyObject> myMap = new HashMap <Integer, MyObject> (); ale wyświetlanie powoduje mój problem z> i <, aby wyświetlić dobrą odpowiedź
franki3xe
Wiem, że pisanie na maszynie jest bolesne, ale próbowałem cię uratować od natychmiastowego -1. W przeciwieństwie do innych komentuję przed ukaraniem (nie zrobiłem -1 dla ciebie).
Adam Gent
0

Proszę użyć HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();

Michael
źródło
0

Nie rozumiem, dlaczego powinienem dodać wymiar (tj. Zrobić int do tablicy), ponieważ potrzebuję tylko przechowywać cyfrę jako klucz.

Tablica jest również obiektem, więc HashMap<int[], MyObject>jest prawidłową konstrukcją, która używa tablic int jako kluczy.

Kompilator nie wie, czego chcesz lub czego potrzebujesz, po prostu widzi konstrukcję językową, która jest prawie poprawna i ostrzega, czego brakuje, aby była w pełni poprawna.

Yoory N.
źródło
1
Uważaj na to, wartość skrótu tablicy nie jest powiązana z jej zawartością, więc dwie tablice o tej samej zawartości mogą hashować do innej wartości, co czyni go bardzo kiepskim kluczem.
john16384
0

Dla kogoś, kto jest zainteresowany taką mapą, ponieważ chcesz zmniejszyć ślad autoboxingu w Javie dla wrapperów nad typami prymitywów, poleciłbym użycie kolekcji Eclipse . Trove nie jest już obsługiwany i uważam, że jest to dość zawodna biblioteka (choć i tak jest dość popularna) i nie można jej porównać z kolekcjami 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));
    }
}

W tym przykładzie powyżej IntObjectHashMap .

Ponieważ potrzebujesz mapowania obiektów int-> , rozważ również użycie YourObjectType[]tablicy lub List<YourObjectType>wartości dostępu według indeksu, ponieważ map jest z natury tablicą asocjacyjną z typem int jako indeksem.

Alex
źródło