Debe usar java.awt.Dimension como su clave.
Dimensión clave = nueva Dimensión (4, 12);
Dimension tiene un método hashCode() muy bueno que produce un hashCode diferente para cada par de enteros positivos, de modo que los hashCodes para (4, 12) y (12, 4) son diferentes. Entonces estos son rápidos para crear instancias y hacer muy buenos hashCodes.
Ojalá hubieran hecho la clase inmutable, pero puedes hacer tu propia clase inmutable modelada en Dimension.
Aquí hay una tabla que muestra el código hash para diferentes valores de anchura y altura:
0 1 2 3 4 <-- width
+--------------------
0 | 0 2 5 9 14
1 | 1 4 8 13
2 | 3 7 12
3 | 6 11
4 | 10
^
|
height
Si sigue las hashcodes con el fin de 0 a 14, verá el patrón.
Aquí está el código que produce este código hash:
public int hashCode() {
int sum = width + height;
return sum * (sum + 1)/2 + width;
}
Usted puede reconocer la fórmula para el número triangular dentro de la última línea. Es por eso que la primera columna de la tabla contiene todos los números triangulares.
Para la velocidad, debe calcular hashCode en el constructor. Para que toda la clase podría tener este aspecto:
public class PairHash {
private final int hash;
public PairHash(int a, int b) {
int sum = a+b;
hash = sum * (sum+1)/2 + a;
}
public int hashCode() { return hash; }
}
Por supuesto, si es probable que tengas un método es igual, pero usted se limita a números enteros positivos que no rebose, puede agregar una forma muy rápida una:
public class PairHash {
// PAIR_LIMIT is 23170
// Keeping the inputs below this level prevents overflow, and guarantees
// the hash will be unique for each pair of positive integers. This
// lets you use the hashCode in the equals method.
public static final int PAIR_LIMIT = (int) (Math.sqrt(Integer.MAX_VALUE))/2;
private final int hash;
public PairHash(int a, int b) {
assert a >= 0;
assert b >= 0;
assert a < PAIR_LIMIT;
assert b < PAIR_LIMIT;
int sum = a + b;
hash = sum * (sum + 1)/2 + a;
}
public int hashCode() { return hash; }
public boolean equals(Object other) {
if (other instanceof PairHash){
return hash == ((PairHash) other).hash;
}
return false;
}
}
Restringimos esto a valores positivos porque los valores negativos producirán algunos códigos hash duplicados. Pero con esta restricción en su lugar, estos son los métodos hashCode() y equals() más rápidos que se pueden escribir. (Por supuesto, puede escribir hashCodes igual de rápido en cualquier clase inmutable calculando el hashCode en el constructor.)
Si no puede vivir con esas restricciones, solo necesita guardar los parámetros.
public class PairHash {
private final int a, b, hash;
public PairHash(int a, int b) {
this.a = a;
this.b = b;
int sum = a+b;
hash = sum * (sum+1)/2 + a;
}
public int hashCode() { return hash; }
public boolean equals(Object other) {
if (other instanceof PairHash) {
PairHash otherPair = (PairHash)other;
return a == otherPair.a && b == otherPair.b;
}
return false;
}
Pero aquí está el truco. No necesitas esta clase en absoluto. Dado que la fórmula le proporciona un número entero único para cada par de números, puede usar ese número entero como su clave de mapa. La clase Integer tiene sus propios métodos fast equals() y hashCode que funcionarán bien. Este método generará la clave hash a partir de dos valores cortos. La restricción es que sus entradas deben ser valores cortos positivos. Esto garantiza que no se desbordará, y al convertir la suma intermedia en una larga, tiene un rango más amplio que el método anterior: funciona con todos los valores cortos positivos.
static int hashKeyFromPair(short a, short b) {
assert a >= 0;
assert b >= 0;
long sum = (long) a + (long) b;
return (int) (sum * (sum + 1)/2) + a;
}
Creo que la cadena delimitada por comas es una buena idea. Uso este enfoque todo el tiempo. – mob