HashMap et int comme clé

104

J'essaye de construire un HashMap qui aura des nombres entiers comme clés et des objets comme valeurs.

Ma syntaxe est:

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

Cependant, l'erreur renvoyée est - Erreur de syntaxe sur le jeton "int", Dimensions attendues après ce jeton - Je ne comprends pas pourquoi je devrais ajouter une dimension (c'est-à-dire: faire de l'int dans un tableau) car je n'ai besoin que de stocker un chiffre comme clé.

"Que pouvais-je faire?"

Merci d'avance! :)

MrD
la source
14
HashMapne gère pas les primitives, juste les objets.
Menno
Question SO connexe , mais avec intla valeur, pas la clé.
cyroxx
5
Utilisez Integerplutôt.
Hot Licks
Est-il préférable de placer automatiquement int en Integer ou simplement de stocker les données sous forme de chaîne, ce qui est plus confortable?
Marcin Erbel le

Réponses:

25

Vous ne pouvez pas utiliser une primitive car HashMap utilise un objet en interne pour la clé. Vous ne pouvez donc utiliser qu'un objet qui hérite d'Object (c'est-à-dire n'importe quel objet).

C'est la fonction put () dans HashMap et comme vous pouvez le voir, elle utilise 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;
}

L'expression "k = e.key" devrait le rendre clair.

Je suggère d'utiliser un wrapper comme Integer et autoboxing.

user1883212
la source
137

Utilisez Integerplutôt.

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

Java ajoutera automatiquement vos intvaleurs primitives aux Integerobjets.

En savoir plus sur l' autoboxing à partir des documentations Oracle Java.

gaborsch
la source
10
Il ne devrait pas non plus nommer une classemyObject
Adam Gent
@AdamGent Correct. Tous les noms de classes doivent commencer par des majuscules, j'ai corrigé le code recommandé.
gaborsch
3
Je sais que tu sais :) Je veux juste m'assurer que l'OP sait / apprend. Pour autant que je sache, il aurait pu mettre un nom de variable dans le paramètre type.
Adam Gent
1
Juste une petite note rapide, il vaut mieux utiliser ArrayMapou SimpleArrayMapsur Android pour économiser de la mémoire et augmenter les performances ( Plus d'informations )
Noah Huppert
42

Pour tous ceux qui codent Java pour les appareils Android et se retrouvent ici: utilisez SparseArraypour de meilleures performances;

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

avec cela, vous pouvez utiliser int au lieu de Integer comme;

int newPos = 3;

myMap.put(newPos, newObject);
myMap.get(newPos);
Stépoïde
la source
7
N'oubliez pas que SparseArray est plus lent que hashmap, mais plus efficace en mémoire. Alors, ne l'utilisez pas sur de grands ensembles de données.
TpoM6oH
Comment SparseArray est-il utilisé pour de meilleures performances alors qu'il est plus lent? Lequel utiliser dans mon jeu Android
Snake
@Snake SparseArraySi vous allouez un tas d'entrées de mémoire et de déballage comme vous le feriez avec a HashMap, le vm devra interrompre plus tôt l'exécution pour le ramasse-miettes. Ceci est important si vous essayez de faire quelque chose fréquemment et rapidement.
Jon
1
Rappelez-vous que la complexité de l'insertion dans SparseArrayest O (n) ( HashMapa O (1) ). C'est important lorsque le nombre d'éléments est important. L'insertion au début d'un tel tableau est beaucoup plus lente.
Vladimir Petrakovich
1
@ M.kazemAkhgary Pas exactement. put()prend O(n)(pas n log n) pour l'insertion au début car il trouve la position puis décale tous les éléments suivants. delete()lui-même prend en effet O(log n), mais la prochaine insertion ou itération à travers des éléments après la suppression nécessitera un garbage collection qui prend O(n).
Vladimir Petrakovich
4

La principale raison pour laquelle HashMap n'autorise pas les clés primitives est que HashMap est conçu de telle manière que pour comparer les clés, il utilise la méthode equals () , et une méthode ne peut être appelée que sur un objet et non sur une primitive.

Ainsi, lorsque int est automatiquement converti en Integer, Hashmap peut appeler la méthode equals () sur l'objet Integer.

C'est pourquoi, vous devez utiliser Integer au lieu de int. Je veux dire que hashmap lève une erreur en mettant int comme clé (je ne connais pas la signification de l'erreur qui est lancée)

Et si vous pensez que, vous pouvez accélérer les performances de Map en créant une primitive comme clé, il existe une bibliothèque appelée FastUtil qui contient une implémentation de Map avec le type int comme clé.

Pour cette raison, il est beaucoup plus rapide que Hashmap

PèreMathew
la source
1
Non, la principale raison de ne pas autoriser les types primitifs est l' effacement de type en Java, qui se transforme effectivement Map<Integer, String>en Map<Object, Object>lors de la compilation. BTW, il y a IdentityHashMap qui utilise l' ==opérateur pour la vérification d'égalité, qui n'autorise toujours pas les types primitifs.
Yoory N.
3

HashMap n'autorise pas les types de données primitifs comme arguments. Il ne peut accepter que des objets donc

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

ne fonctionnera pas.

Vous devez changer la déclaration en

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

donc même quand tu fais ce qui suit

myMap.put(2,myObject);

Le type de données primitif est automatiquement renvoyé à un objet Integer.

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

Vous pouvez en savoir plus sur l'autoboxing ici http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

Lakshmi
la source
1

utiliser int comme objet pas comme type primitif

HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();
franki3xe
la source
J'ai écrit HashMap <Integer, MyObject> myMap = new HashMap <Integer, MyObject> (); mais en affichant mon problème avec> et <pour afficher une bonne réponse
franki3xe
Je sais que c'est douloureux à taper mais j'essayais de vous sauver de l'immédiat -1. Je contrairement aux autres commenter avant de pénaliser (je n'ai pas -1 vous).
Adam Gent
0

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

Michael
la source
0

Je ne comprends pas pourquoi je devrais ajouter une dimension (c'est-à-dire: faire de l'int dans un tableau) car je n'ai besoin que de stocker un chiffre comme clé.

Un tableau est également un objet, tout HashMap<int[], MyObject>comme une construction valide qui utilise des tableaux int comme clés.

Le compilateur ne sait pas ce que vous voulez ou ce dont vous avez besoin, il voit juste une construction de langage qui est presque correcte et avertit ce qui manque pour qu'elle soit entièrement correcte.

Yoory N.
la source
1
Attention, la valeur de hachage d'un tableau n'est pas liée à son contenu, donc deux tableaux avec le même contenu peuvent hacher une valeur différente, ce qui en fait une clé très pauvre.
john16384
0

Pour quelqu'un qui s'intéresse à une telle carte parce que vous souhaitez réduire l' empreinte de l'autoboxing en Java des wrappers sur les types primitifs, je recommanderais d'utiliser les collections Eclipse . Trove n'est plus pris en charge , et je pense que c'est une bibliothèque assez peu fiable (bien qu'elle soit de toute façon très populaire) et ne peut pas être comparée aux collections 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));
    }
}

Dans cet exemple ci-dessus IntObjectHashMap .

Comme vous avez besoin d'un mappage d' objets int-> , considérez également l'utilisation du YourObjectType[]tableau ou List<YourObjectType>et accédez aux valeurs par index, car map est, par nature, un tableau associatif avec le type int comme index.

Alex
la source