HashMap e int como clave

104

Estoy tratando de construir un HashMap que tendrá enteros como claves y objetos como valores.

Mi sintaxis es:

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

Sin embargo, el error devuelto es - Error de sintaxis en el token "int", Dimensiones esperadas después de este token - No entiendo por qué debería agregar una dimensión (es decir, convertir el int en una matriz) ya que solo necesito almacenar un dígito como clave.

¿Qué puedo hacer?

¡Gracias por adelantado! :)

MrD
fuente
14
HashMapno maneja primitivas, solo objetos.
Menno
Pregunta SO relacionada , pero intsiendo el valor, no la clave.
cyroxx
5
Úselo en su Integerlugar.
Hot Licks
¿Es mejor autoboxing int a Integer o simplemente almacenar datos como String, que es más cómodo?
Marcin Erbel

Respuestas:

25

No puede usar una primitiva porque HashMap usa el objeto internamente para la clave. Por lo tanto, solo puede usar un objeto que herede de Object (es decir, cualquier objeto).

Esa es la función put () en HashMap y, como puede ver, usa 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;
}

La expresión "k = e.key" debería dejarlo claro.

Sugiero usar un contenedor como Integer y autoboxing.

usuario1883212
fuente
137

Úselo en su Integerlugar.

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

Java automáticamente encuadrará sus intvalores primitivos paraInteger objetos.

Lea más sobre el autoboxing en la documentación de Oracle Java.

Gaborsch
fuente
10
Tampoco debería nombrar una clasemyObject
Adam Gent
@AdamGent Correcto. Todos los nombres de las clases deben comenzar con mayúsculas, corregí el código recomendado.
gaborsch
3
Sé que lo sabes :) Solo quiero asegurarme de que el OP sepa / aprenda. Por lo que sé, podría haber estado poniendo un nombre de variable en el parámetro de tipo.
Adam Gent
1
Solo una pequeña nota rápida, es mejor usar ArrayMapo SimpleArrayMapen Android para ahorrar memoria y aumentar el rendimiento ( Más información )
Noah Huppert
42

Para todos los que codifican Java para dispositivos Android y terminan aquí: úselo SparseArraypara un mejor rendimiento;

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

con esto puedes usar int en lugar de Integer like;

int newPos = 3;

myMap.put(newPos, newObject);
myMap.get(newPos);
Estepoide
fuente
7
Recuerde que SparseArray es más lento que hashmap, pero más eficiente en memoria. Por lo tanto, no lo use en grandes conjuntos de datos.
TpoM6oH
¿Cómo se usa SparseArray para un mejor rendimiento mientras es más lento? Cuál usar en mi juego de Android
Snake
@Snake SparseArraySi asigna un montón de entradas de boxing y unboxing de memoria como lo haría con a HashMap, la máquina virtual deberá pausar la ejecución para la recolección de basura antes. Esto es importante si está intentando hacer algo con frecuencia y rapidez.
Jon
1
Recuerde que la complejidad de la inserción en SparseArrayes O (n) ( HashMaptiene O (1) ). Es importante cuando el número de elementos es grande. La inserción al principio de dicha matriz es mucho más lenta.
Vladimir Petrakovich
1
@ M.kazemAkhgary No exactamente. put()toma O(n)(no n log n) para la inserción al inicio porque encuentra la posición y luego cambia todos los elementos siguientes. delete()sí mismo toma O(log n), pero la siguiente inserción o iteración a través de elementos después de eliminar requerirá una recolección de basura que toma O(n).
Vladimir Petrakovich
4

La razón principal por la que HashMap no permite primitivas como claves es que HashMap está diseñado de tal manera que para comparar las claves, utiliza equals () método , y un método puede ser llamado solo en un objeto, no en una primitiva.

Por lo tanto, cuando int se coloca automáticamente en Integer, Hashmap puede llamar al método equals () en el objeto Integer.

Por eso, debe usar Integer en lugar de int. Me refiero a que hashmap arroja un error al poner int como clave (no sé el significado del error que se arroja)

Y si piensa eso, puede hacer que el rendimiento de Map sea más rápido haciendo una primitiva como clave, hay una biblioteca llamada FastUtil que contiene una implementación de Map con el tipo int como clave.

Debido a esto, es mucho más rápido que Hashmap

PadreMathew
fuente
1
No, la razón principal para no permitir tipos primitivos es el borrado de tipos en Java, que efectivamente se convierte Map<Integer, String>en Map<Object, Object>durante la compilación. Por cierto, hay IdentityHashMap que usa el ==operador para la verificación de igualdad, que aún no permite tipos primitivos.
Yoory N.
3

HashMap no permite tipos de datos primitivos como argumentos. Solo puede aceptar objetos

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

no trabajará.

Tienes que cambiar la declaración a

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

así que incluso cuando haces lo siguiente

myMap.put(2,myObject);

El tipo de datos primitivo se coloca automáticamente en un objeto Integer.

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

Puede leer más sobre el autoboxing aquí http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

Lakshmi
fuente
1

use int como Object no como tipo primitivo

HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();
franki3xe
fuente
He escrito HashMap <Integer, MyObject> myMap = new HashMap <Integer, MyObject> (); pero mostrando hacer mi problema con> y <para mostrar una buena respuesta
franki3xe
Sé que es doloroso escribir, pero estaba tratando de salvarte de inmediato -1. A diferencia de lo que otros comentan antes de penalizar (yo no te -1).
Adam Gent
0

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

Miguel
fuente
0

No entiendo por qué debería agregar una dimensión (es decir, convertir el int en una matriz) ya que solo necesito almacenar un dígito como clave.

Una matriz también es un objeto, por lo que HashMap<int[], MyObject> es una construcción válida que usa matrices int como claves.

El compilador no sabe lo que quiere o lo que necesita, solo ve una construcción de lenguaje que es casi correcta y advierte lo que falta para que sea completamente correcto.

Yoory N.
fuente
1
Tenga cuidado con esto, el valor hash de una matriz no está relacionado con su contenido, por lo que dos matrices con el mismo contenido pueden cambiar a un valor diferente, lo que la convierte en una clave muy pobre.
john16384
0

Para alguien que esté interesado en un mapa de este tipo porque desea reducir la huella de autoboxing en Java de envoltorios sobre tipos primitivos, recomendaría usar colecciones de Eclipse . Trove ya no es compatible , y creo que es una biblioteca bastante poco confiable (aunque de todos modos es bastante popular) y no se puede comparar con las colecciones de 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));
    }
}

En este ejemplo anterior IntObjectHashMap .

Como necesita el mapeo int-> object , también considere el uso de YourObjectType[]matriz o List<YourObjectType>valores de acceso por índice, ya que map es, por naturaleza, una matriz asociativa con el tipo int como índice.

Alex
fuente