我正在考虑使用Double作为HashMap的关键,但我知道浮点数比较是不安全的,这让我思考.Double类的equals方法也不安全吗?如果那样则意味着hashCode方法可能也是错误的.这意味着使用Double作为HashMap的关键将导致不可预测的行为.
任何人都可以在这里证实我的任何猜测吗?
Dav*_*itz 16
简短的回答:不要这样做
答案很长:以下是密钥的计算方法:
实际的键将是一个java.lang.Double对象,因为键必须是对象.这是它的hashCode()方法:
public int hashCode() {
long bits = doubleToLongBits(value);
return (int)(bits ^ (bits >>> 32));
}
Run Code Online (Sandbox Code Playgroud)
该doubleToLongBits()方法基本上占用8个字节并将其表示为long.所以这意味着double的计算中的微小变化意味着很多,你将有关键的失误.
如果你可以在点之后满足给定的点数 - 乘以10 ^(点后面的位数)并转换为int(例如 - 对于2位乘以100).
它会更安全.
我想你是对的.虽然双打的哈希值是整数,但是double可能会破坏哈希值.这就是为什么,正如Josh Bloch在Effective Java中提到的,当你使用double作为哈希函数的输入时,你应该使用doubleToLongBits().同样,使用floatToIntBits表示浮点数.
特别是,根据Josh Bloch的配方使用double作为哈希,你会做:
public int hashCode() {
int result = 17;
long temp = Double.doubleToLongBits(the_double_field);
result = 37 * result + ((int) (temp ^ (temp >>> 32)));
return result;
}
Run Code Online (Sandbox Code Playgroud)
这来自Effective Java的第8项,"当覆盖equals时总是覆盖hashCode".它可以在本书章节的pdf中找到.
希望这可以帮助.
这取决于你将如何使用它.
如果您对能够根据完全相同的位模式(或可能是等效的位模式,例如+/- 0和各种NaN)找到值感到满意,那么它可能没问题.
特别是,所有NaN最终都被视为相等,但+ 0和-0将被视为不同.来自以下文档Double.equals:
请注意,在大多数情况下,对于Double,d1和d2类的两个实例,d1.equals(d2)的值为true,当且仅当
d1.doubleValue()== d2.doubleValue()的值也为true.但是,有两个例外:
- 如果d1和d2都表示Double.NaN,则equals方法返回true,即使Double.NaN == Double.NaN的值为false.
- 如果d1表示+0.0而d2表示-0.0,反之亦然,则等值测试的值为false,即使+0.0 == - 0.0的值为true.
此定义允许哈希表正常运行.
最有可能的是你对"非常接近关键的数字"感兴趣,这使得它更不可行.特别是如果你要进行一组计算以获得一次密钥,那么第二次获得密钥的另一组计算,你就会遇到问题.
问题不是哈希码而是双精度.这会导致一些奇怪的结果.例:
double x = 371.4;
double y = 61.9;
double key = x + y; // expected 433.3
Map<Double, String> map = new HashMap<Double, String>();
map.put(key, "Sum of " + x + " and " + y);
System.out.println(map.get(433.3)); // prints null
Run Code Online (Sandbox Code Playgroud)
计算值(键)是"433.29999999999995",它不是与433.3的EQUALS,所以你没有在Map中找到条目(哈希码可能也不同,但这不是主要问题).
如果你使用
map.get(key)
Run Code Online (Sandbox Code Playgroud)
它应该找到条目... []]
| 归档时间: |
|
| 查看次数: |
20407 次 |
| 最近记录: |