您应该使用 java.awt.Dimension 作为您的密钥。
维度键 = new Dimension(4, 12);
Dimension 有一个非常好的 hashCode() 方法,它为每对正整数生成不同的 hashCode,因此 (4, 12) 和 (12, 4) 的 hashCode 不同。所以这些可以快速实例化并制作非常好的哈希码。
我真希望他们使类不可变,但您可以根据 Dimension 创建自己的不可变类。
这是一个表格,显示了不同宽度和高度值的 hashCode:
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
如果您按照从 0 到 14 的顺序执行 hashCodes,您会看到该模式。
这是产生这个 hashCode 的代码:
public int hashCode() {
int sum = width + height;
return sum * (sum + 1)/2 + width;
}
您可能会在最后一行中认出三角数的公式。这就是表格的第一列包含所有三角数的原因。
为了速度,你应该在构造函数中计算 hashCode。所以你的整个班级可能看起来像这样:
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; }
}
当然,如果你可能需要一个 equals 方法,但你限制自己使用不会溢出的正整数,你可以添加一个非常快的方法:
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;
}
}
我们将此限制为正值,因为负值会产生一些重复的哈希码。但是有了这个限制,这些是可以编写的最快的 hashCode() 和 equals() 方法。 (当然,您可以通过在构造函数中计算 hashCode,在任何不可变类中以同样快的速度编写 hashCode。)
如果你不能忍受这些限制,你只需要保存参数。
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;
}
但这是最重要的。你根本不需要这门课。由于该公式为每对数字提供了一个唯一的整数,因此您可以使用该整数作为映射键。 Integer 类有自己的快速 equals() 和 hashCode 方法,它们可以正常工作。此方法将从两个短值生成哈希键。限制是您的输入必须是正短值。这保证不会溢出,并且通过将中间和转换为 long,它比以前的方法具有更广泛的范围:它适用于所有正的 short 值。
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;
}