HashMap e int come chiave


104

Sto cercando di costruire una HashMap che avrà numeri interi come chiavi e oggetti come valori.

La mia sintassi è:

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

Tuttavia, l'errore restituito è - Errore di sintassi sul token "int", Dimensioni previste dopo questo token - Non capisco perché dovrei aggiungere una dimensione (ad esempio: trasformare l'int in un array) poiché ho solo bisogno di memorizzare una cifra come chiave.

Cosa potevo fare?

Grazie in anticipo! :)


14
HashMapnon gestisce primitive, solo oggetti.
Menno

Domanda SO correlata , ma con l' intessere il valore, non la chiave.
cyroxx

5
Usa Integerinvece.
Hot Licks

È meglio autobox int a Integer o semplicemente memorizzare i dati come una stringa, che è più comodo?
Marcin Erbel

Risposte:


25

Non puoi usare una primitiva perché HashMap usa l'oggetto internamente per la chiave. Quindi puoi usare solo un oggetto che eredita da Object (cioè qualsiasi oggetto).

Questa è la funzione put () in HashMap e come puoi vedere usa Object per 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;
}

L'espressione "k = e.key" dovrebbe renderlo chiaro.

Suggerisco di utilizzare un wrapper come Integer e autoboxing.


137

Usa Integerinvece.

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

Java autobox automaticamente inti valori primitivi negli Integeroggetti.

Ulteriori informazioni sull'autoboxing dalle documentazioni Oracle Java.


10
Inoltre, non dovrebbe nominare una classemyObject
Adam Gent il

@AdamGent Correct. Tutti i nomi delle classi dovrebbero iniziare con le maiuscole, ho corretto il codice consigliato.
gaborsch

3
So che lo sai :) Voglio solo assicurarmi che l'OP lo sappia / impari. Per quanto ne so, avrebbe potuto inserire un nome di variabile nel parametro type.
Adam Gent,

1
Solo una piccola nota veloce, è meglio usare ArrayMapo SimpleArrayMapsu Android per risparmiare memoria e aumentare le prestazioni ( Maggiori informazioni )
Noah Huppert

42

Per tutti coloro che codificano Java per dispositivi Android e finiscono qui: utilizzare SparseArrayper prestazioni migliori;

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

con questo puoi usare int invece di Integer like;

int newPos = 3;

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

7
Ricorda che SparseArray è più lento di hashmap, ma più efficiente in termini di memoria. Quindi, non usarlo su set di dati di grandi dimensioni.
TpoM6oH

Come viene utilizzato SparseArray per ottenere prestazioni migliori mentre è più lento? Quale usare nel mio gioco Android
Snake

@Snake SparseArraySe si alloca un mucchio di int di boxing e unboxing di memoria come si farebbe con a HashMap, la VM dovrà sospendere prima l'esecuzione per la garbage collection. Questo è importante se stai cercando di fare qualcosa frequentemente e rapidamente.
Jon,

1
Ricorda che la complessità dell'inserimento in SparseArrayè O (n) ( HashMapha O (1) ). È importante quando il numero di elementi è elevato. L'inserimento all'inizio di tale matrice è molto più lento.
Vladimir Petrakovich

1
@ M.kazemAkhgary Non esattamente. put()accetta O(n)(non n log n) l'inserimento all'inizio perché trova la posizione e quindi sposta tutti gli elementi successivi. delete()se stesso richiede effettivamente O(log n), ma il successivo inserimento o iterazione di elementi dopo l'eliminazione richiederà una garbage collection che accetta O(n).
Vladimir Petrakovich


4

Il motivo principale per cui HashMap non consente la primitiva come chiavi è che HashMap è progettato in modo tale che per confrontare le chiavi, utilizza il metodo equals () e un metodo può essere chiamato solo su un oggetto non su una primitiva.

Pertanto, quando int viene impostato automaticamente su Integer, Hashmap può chiamare il metodo equals () sull'oggetto Integer.

Ecco perché dovresti usare Integer invece di int. Intendo dire hashmap genera un errore mentre inserisce int come chiave (non si conosce il significato dell'errore che viene lanciato)

E se pensi che puoi rendere le prestazioni di Map più veloci creando una primitiva come chiave, c'è una libreria chiamata FastUtil che contiene un'implementazione Map con tipo int come chiave.

Per questo motivo è molto più veloce di Hashmap


1
No, il motivo principale per non permettere tipi primitivi è la cancellazione di tipo in Java, che si trasforma in modo efficace Map<Integer, String>in Map<Object, Object>fase di compilazione. BTW, c'è IdentityHashMap che utilizza l' ==operatore per il controllo dell'uguaglianza, che ancora non consente i tipi primitivi.
Yoory N.

3

HashMap non consente tipi di dati primitivi come argomenti. Può accettare solo oggetti così

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

non funzionerà.

Devi cambiare la dichiarazione in

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

quindi anche quando fai quanto segue

myMap.put(2,myObject);

Il tipo di dati primitivo viene convertito automaticamente in un oggetto Integer.

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

Puoi leggere di più sull'autoboxing qui http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html



1

usa int come Object non come tipo primitivo

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

Ho scritto HashMap <Integer, MyObject> myMap = new HashMap <Integer, MyObject> (); ma la visualizzazione crea il mio problema con> e <per visualizzare una buona risposta
franki3xe

So che è doloroso digitare ma stavo cercando di salvarti dall'immediato -1. Io a differenza di altri commento prima di penalizzare (non ho -1 tu).
Adam Gent

0

Si prega di utilizzare HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();


0

Non capisco perché dovrei aggiungere una dimensione (ad esempio: rendere int in un array) poiché ho solo bisogno di memorizzare una cifra come chiave.

Un array è anche un oggetto, quindi HashMap<int[], MyObject> è un costrutto valido che utilizza gli array int come chiavi.

Il compilatore non sa cosa vuoi o cosa ti serve, vede solo un costrutto di linguaggio che è quasi corretto e avverte cosa manca affinché sia ​​completamente corretto.


1
Fai attenzione, il valore hash di un array non è correlato al suo contenuto, quindi due array con lo stesso contenuto possono eseguire l'hashing con un valore diverso rendendolo una chiave molto scadente.
john16384

0

Per qualcuno che è interessato a una tale mappa perché si desidera ridurre l' impronta dell'autoboxing in Java dei wrapper rispetto ai tipi di primitive, consiglierei di utilizzare le raccolte Eclipse . Trove non è più supportato e credo che sia una libreria abbastanza inaffidabile (sebbene sia comunque abbastanza popolare) e non possa essere confrontata con le raccolte 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));
    }
}

In questo esempio sopra IntObjectHashMap .

Dato che hai bisogno della mappatura int-> oggetto , considera anche l'uso di YourObjectType[]array o List<YourObjectType>e accedi ai valori per indice, poiché map è, per natura, un array associativo con tipo int come index.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.