2009-07-27 9 views
11

Quiero almacenar ciertos objetos en un HashMap. El problema es que generalmente usas un solo objeto como clave. (Puede, por ejemplo, usar un String.) Lo que quiero hacer es usar un objeto múltiple. Por ejemplo, una clase y una cadena. ¿Hay una manera simple y limpia de implementar eso?Usando dos (o más) objetos como una clave HashMap

Respuesta

14

clave Debe implementar el código hash e iguales. Si se trata de un SortedMap, también tiene que implementa la interfaz Comparable

public class MyKey implements Comparable<MyKey> 
{ 
private Integer i; 
private String s; 
public MyKey(Integer i,String s) 
{ 
this.i=i; 
this.s=s; 
} 

public Integer getI() { return i;} 
public String getS() { return s;} 

@Override 
public int hashcode() 
{ 
return i.hashcode()+31*s.hashcode(); 
} 

@Override 
public boolean equals(Object o) 
{ 
if(o==this) return true; 
if(o==null || !(o instanceof MyKey)) return false; 
MyKey cp= MyKey.class.cast(o); 
return i.equals(cp.i) && s.equals(cp.s); 
    } 

    public int compareTo(MyKey cp) 
    { 
    if(cp==this) return 0; 
    int i= i.compareTo(cp.i); 
    if(i!=0) return i; 
    return s.compareTo(cp.s); 
    } 


@Override 
    public String toString() 
     { 
     return "("+i+";"+s+")"; 
     } 

    } 

public Map<MyKey,String> map= new HashMap<MyKey,String>(); 
map.put(new MyKey(1,"Hello"),"world"); 
8

que tienden a utilizar una lista

map.put(Arrays.asList(keyClass, keyString), value) 
+1

¿El hashcode de Array.asList no es específico de esa lista? –

+1

No, el código hash de cualquier 'Lista' (o al menos cualquier' AbstractList', que 'Arrays.asList' es) está determinado por los códigos hash de sus elementos. Lo busqué porque tenía el mismo pensamiento. –

+2

Fácil de hacer, pero tiene el inconveniente de no documentar lo que pertenece a la lista. ¿Era clase, cuerda? o la cadena primero? o el nombre de clase y la cadena? –

1

Se puede crear una clase de soporte que contiene la clase y la cadena que desea que las teclas.

public class Key { 

    public MyClass key_class; 
    public String key_string; 

    public Key(){ 
     key_class = new MyClass(); 
     key_string = ""; 
    } 

} 

Probablemente no sea la mejor solución, pero es una posibilidad.

+3

Cualquier clase utilizada como clave necesita anular equals() y hashCode() correctamente. – notnoop

+2

Me gusta el enfoque, pero agregar un código hash y el método igual es obligatorio para el caso de uso. También lo haría inmutable. –

+0

@msaeed y @Jens Schauder, gracias por los consejos. –

4

La manera más fácil que conozco es hacer una clase contenedora y anular hashmap e iguales. Por ejemplo:

public class KeyClass { 

    private String element1; 
    private String element2; 

    //boilerplate code here 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof KeyClass) { 
      return element1.equals(((KeyClass)obj).element1) && 
       element2.equals(((KeyClass)obj).element2); 
     } 
     return false; 
    } 

    @Override 
    public int hashCode() { 
     return (element1 + element2).hashcode(); 
    } 
} 

Por supuesto, yo recomendaría usar un StringBuilder y cualquier otra cosa, pero de esta manera se ha anulado los iguales y código hash, lo que permite un control de hash y la igualdad en sus varias claves.

Además, recomendaría hacer los objetos inmutables (no editables) por razones de seguridad, pero eso es pura preferencia.

2

¿Quiere decir que el objeto estará marcado por dos teclas, o más bien por una clave que consta de dos cosas.

Si quiere el primer caso. Es decir, una objeción marcada por dos teclas, digamos una clase o un objeto, debe usar dos mapas.

Map<Key1, value> 

Map<Key2, value> 

En el segundo caso se necesita un mapa de los mapas, por lo que:

Map<Key1, Map<Key2, value>> 
0

Hay algunos lugares donde la gente sugiere crear una clase "Clave" que contenga las otras, estoy totalmente de acuerdo. Solo pensé en agregar una sugerencia útil.

Si usa eclipse o netbeans, tienen una buena opción: puede decirle a Eclipse que cree métodos iguales y de código hash basados ​​en uno o más miembros. Así que solo selecciona el miembro (o miembros) que desea recuperar y NB crea la mayor parte del código que necesitaría escribir para usted.

por supuesto cuando solo quiero recuperar por un objeto, a menudo solo delegado el código hash e iguala los métodos a ese objeto (delegar iguales podría ser problemático porque significaría que una de las clases "titular de clave" sería igual al objeto que es que es clave, pero eso es bastante fija fácilmente (y no habría normalmente efectuar nada de todos modos)

tan fuera de la parte superior de mi cabeza:

class KeyHolder { 
    public final String key; 
    public final Object storeMe; 

    public KeyHolder(String key, Object storeMe) { 
     this.key=key; 
     this.storeMe=storeMe; 
    } 

    public equals(Object o) { 
     return (o instanceof KeyHolder && ((KeyHolder)o).key.equals(key)); 
    } 

    public hashcode() { 
     return key.hashCode(); 
    } 
} 

eso es todo lo que hay que hacer, y eclipse hará las dos últimas por ti si lo pides.

Por cierto, sé que tengo miembros públicos, un miembro final público es exactamente lo mismo que tener un captador: realmente no es una idea terrible. Últimamente estoy empezando a utilizar este patrón en pequeñas clases de utilidad como esta. Si el miembro no fuera final, sería peor porque sería como tener un colocador (algo que trato de evitar en estos días).

0

Uno puede resolver este problema usando la colección de commons de apache MultiKey class de lib. Aquí hay un ejemplo simple:

import org.apache.commons.collections.keyvalue.MultiKey; 

HashMap map = new HashMap(); 
MultiKey multiKey = new MultiKey(key1, key2); 

map.put(multikey,value); 

//to get 
map.get(new MultiKey(key1,key2)); 
+1

Tenga en cuenta que esto duplica [respuesta de Clay] (http://stackoverflow.com/a/1190244/157247), a pesar de que usted ha proporcionado un ejemplo. –

Cuestiones relacionadas