HashMap e int como chave


104

Estou tentando construir um HashMap que terá inteiros como chaves e objetos como valores.

Minha sintaxe é:

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

No entanto, o erro retornado é - Erro de sintaxe no token "int", Dimensões esperadas após este token - Não entendo por que devo adicionar uma dimensão (ou seja: transformar o int em uma matriz), pois só preciso armazenar um dígito como chave.

O que eu poderia fazer?

Desde já, obrigado! :)


14
HashMapnão lida com primitivos, apenas objetos.
Menno

Pergunta SO relacionada , mas intsendo o valor, não a chave.
cyroxx de

5
Use em seu Integerlugar.
Hot Licks de

É melhor autobox de int para Integer ou apenas armazenar dados como String, o que é mais confortável?
Marcin Erbel

Respostas:


25

Você não pode usar uma primitiva porque o HashMap usa o objeto internamente para a chave. Portanto, você só pode usar um objeto que herda de Object (ou seja, qualquer objeto).

Essa é a função put () em HashMap e como você pode ver, ela usa Object para 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;
}

A expressão "k = e.key" deve deixar isso claro.

Eu sugiro usar um wrapper como Integer e autoboxing.


137

Use em seu Integerlugar.

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

Java irá autobox automaticamente seus intvalores primitivos para Integerobjetos.

Leia mais sobre autoboxing nas documentações do Oracle Java.


10
Ele também não deve nomear uma classemyObject
Adam Gent

@AdamGent Correct. Todos os nomes de classes deveriam começar com letras maiúsculas, eu corrigi o código recomendado.
gaborsch de

3
Eu sei que você sabe :) Só quero ter certeza de que o OP sabe / aprende. Pelo que sei, ele poderia estar colocando um nome de variável no parâmetro de tipo.
Adam Gent,

1
Apenas uma pequena nota rápida, é melhor usar o ArrayMapou SimpleArrayMapno Android para economizar memória e aumentar o desempenho ( Mais informações )
Noah Huppert

42

Para todos que codificam Java para dispositivos Android e acabam aqui: use SparseArraypara melhor desempenho;

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

com isso você pode usar int em vez de Integer like;

int newPos = 3;

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

7
Lembre-se de que SparseArray é mais lento que o hashmap, mas tem mais eficiência de memória. Portanto, não o use em grandes conjuntos de dados.
TpoM6oH

Como o SparseArray é usado para obter melhor desempenho enquanto é mais lento? Qual usar no meu jogo Android
Snake

@Snake SparseArraySe você alocar um monte de ints de boxing e unboxing de memória como faria com um HashMap, o VM precisará pausar a execução para a coleta de lixo mais cedo. Isso é importante se você estiver tentando fazer algo com frequência e rapidez.
Jon

1
Lembre-se de que a complexidade de inserção em SparseArrayé O (n) ( HashMaptem O (1) ). É importante quando o número de elementos é grande. A inserção no início dessa matriz é muito mais lenta.
Vladimir Petrakovich

1
@ M.kazemAkhgary Não exatamente. put()leva O(n)(não n log n) para inserção no início porque encontra a posição e, em seguida, desloca todos os elementos seguintes. delete()em si de fato leva O(log n), mas a próxima inserção ou iteração por meio de elementos após a exclusão exigirá uma coleta de lixo que leva O(n).
Vladimir Petrakovich


4

O principal motivo do HashMap não permitir primitivas como chaves é que o HashMap é projetado de tal forma que, para comparar as chaves, faz uso do método equals () , e um método pode ser chamado apenas em um objeto que não está em uma primitiva.

Assim, quando int é autoboxed para Integer, o Hashmap pode chamar o método equals () no objeto Integer.

É por isso que você deve usar Integer em vez de int. Quer dizer, o hashmap lança um erro ao colocar int como uma chave (não sei o significado do erro que é lançado)

E se você pensa assim, pode tornar o desempenho do Map mais rápido tornando uma primitiva como chave, há uma biblioteca chamada FastUtil que contém uma implementação de Map com tipo int como chave.

Por causa disso, é muito mais rápido que o Hashmap


1
Não, o principal motivo para não permitir tipos primitivos é o apagamento de tipo em Java, que efetivamente se Map<Integer, String>transforma Map<Object, Object>durante a compilação. BTW, existe IdentityHashMap que usa ==operador para verificação de igualdade, que ainda não permite tipos primitivos.
Yoory N.

3

O HashMap não permite tipos de dados primitivos como argumentos. Ele só pode aceitar objetos então

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

não funciona.

Você tem que alterar a declaração para

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

então, mesmo quando você faz o seguinte

myMap.put(2,myObject);

O tipo de dados primitivo é autoboxed para um objeto Integer.

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

Você pode ler mais sobre autoboxing aqui http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html



1

use int como objeto, não como tipo primitivo

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

Eu escrevi HashMap <Integer, MyObject> myMap = new HashMap <Integer, MyObject> (); mas exibindo torna meu problema com> e <para exibir uma boa resposta
franki3xe

Eu sei que é doloroso digitar, mas eu estava tentando salvá-lo do imediato -1. Ao contrário de outros comentar antes de penalizar (eu não fiz -1 você).
Adam Gent,

0

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


0

Não entendo por que devo adicionar uma dimensão (ou seja: fazer o int em uma matriz), pois só preciso armazenar um dígito como chave.

Um array também é um Object, portanto HashMap<int[], MyObject>é uma construção válida que usa arrays int como chaves.

O compilador não sabe o que você quer ou precisa, ele apenas vê uma construção de linguagem que está quase correta e avisa o que está faltando para que ela esteja totalmente correta.


1
Tenha cuidado com isso, o valor hash de uma matriz não está relacionado ao seu conteúdo, portanto, duas matrizes com o mesmo conteúdo podem hash para um valor diferente, tornando-se uma chave muito ruim.
john16384

0

Para alguém que está interessado em tal mapa porque deseja reduzir a área de cobertura do autoboxing em Java de wrappers sobre tipos primitivos, eu recomendaria usar coleções Eclipse . Trove não é mais suportado , e acredito que seja uma biblioteca pouco confiável (embora seja bastante popular de qualquer maneira) e não poderia ser comparada com as coleções do 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));
    }
}

Neste exemplo acima, IntObjectHashMap .

Como você precisa de mapeamento int-> objeto , também considere o uso de YourObjectType[]array ou List<YourObjectType>e valores de acesso por índice, já que map é, por natureza, um array associativo com tipo int como índice.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.