2011-02-14 22 views
5

Quiero implementar un HashMap con una clave con 2 componentes. Ex.Java Collection con 2 claves

Pseudocode: 

Key = <Component1, Component2> 
CollName<Key, Val> coll = new CollName<Key, Val>; 

¿Cómo puedo implementar esto en Java, teniendo en cuenta la velocidad y el tamaño de la colección. Gracias: D

Respuesta

7

Es necesario un ayudante de clase (clave compuesta) que mantiene sus dos llaves

public class CompositeKey<... , ...> { 
    ... component1; 
    ... component2; 

    // getter , setter, ... 

    // equals 

    // hashcode() 
} 

y luego se puede utilizar como clave:

CompositeKey cKey = new CompositeKey(1,2); 
Map x.put(cKey,val); 

Es muy importante aquí implementar equals() y hashCode() de una buena manera. La mayoría de los IDE pueden ayudarlo aquí. Es importante para hashCode que devuelva un valor "único" para evitar colisiones hash de las claves (es decir, devolver un valor constante es el peor de los casos, ya que todos los valores terminarían en el mismo contenedor). Muchas implementaciones de código hash hacer algo a lo largo

hashcode = component1.hashCode() + 37* component2.hashCode(); 

Si desea más detalles, desenterrar cualquier libro de CS que habla de algoritmos de hash.

Si desea utilizar eso para la persistencia, también eche un vistazo a this blog post.

+0

@Hieko: Inventive.¿Conoces una fuente que explique las clases de ayuda porque no estoy familiarizado con el concepto? –

+1

Una clase de ayuda no es un concepto especial como tal, es solo una clase normal que envuelve sus dos subobjetos y los trata como si fueran uno solo. Vea mi ejemplo a continuación para obtener un ejemplo de código más detallado. –

+0

@Hieko El problema clave radica en cómo implementar equals y hashcode correctamente. –

2

No puede crear directamente un Mapa con dos teclas, sin embargo, puede combinar las dos.

El método más simple es serializarlos en una cadena y combinarlos.

String key = obj1.toString() + "-" + obj2.toString(); 
myMap.put(key, myValue); 

suponiendo que los objetos se pueden serializar fácilmente en una cadena que sería única.

Si este no es el caso, la mejor opción es crear un objeto envoltorio. Debería definir un objeto que anule el método equals() y hashCode().

Como ejemplo aproximado

class CombinedKey{ 
    private MyClass object1; 
    private MyClass object2; 

    public CombinedKey(MyClass object1, MyClass object2){ 
     this.object1 = object1; 
     this.object2 = object2; 
    } 
    public int hashCode(){ 
     return object1.hashCode() + object2.hashCode(); 
    } 

    @Override 
    public Boolean equals(Object otherObject){ 
     if(otherObject == null || otherObject.getObject1() == null) return false; 
     return object1.equals(otherObject.getObject1()) && object2.equals(otherObject.getObject2(); 
    } 

    public MyClass getObject1() { return object1; } 
    public MyClass getObject2() { return object2; } 

} 

(También puede ser que desee considerar el uso de medicamentos genéricos para definir esta clase para que pueda ser reutilizado en otros escenarios)

Uso:

Map<CombinedKey, Object> myMap = new HashMap<CombinedKey, Object>(); 
myMap.put(new CombinedKey(obj1, obj2), value); 
+3

De acuerdo con su respuesta. Tenga en cuenta que el método es igual a() firma, no se anula desde la clase Object. –

+1

Me recuerda a las claves compuestas en las bases de datos. –

+2

Tenga en cuenta que para un par de claves (a, b) esta implementación devuelve el mismo código hash que para (b, a) que crea colisiones hash, lo que puede limitar el rendimiento (algo). –

0

Es un uso común de HashMap, el punto es que debe definir (anular) igual que() y hashCode() en la clase Key correctamente.

0

Una buena alternativa al uso de un CompositKey/Pair/Tuple es utilizar un List. List implementaciones ya tienen un equals() y hashCode() bien definidos y son fáciles de crear usando Arrays.asList()