我写了一个哈希图并用键/值条目填充它。值是对象。该地图包含至少 10,000 个条目。稍后当我想使用某个键获取值时,地图似乎找不到这个条目。这太奇怪了。即使每次它在不同的条目上失败。我能做些什么来解决这个问题?我正在使用 weblogic 作为服务器。我应该使用任何环境值吗?
4 回答
以下是一些可能导致条目“丢失”的情况:
在您的关键对象上错误地实现了 equals / hashcode 方法。这两种方法需要遵守“契约”才能使哈希表正常工作。最重要的属性是:
key1.equals(key2) IMPLIES key1.hashcode() == key2.hashcode
在映射中使用键时更改的可变键对象。特别是,如果 key 改变导致 key 的 hashcode 改变,它就会丢失。(在这种情况下,如果您遍历整个地图,条目将显示出来。但是使用 has lookup 的地图操作不会找到它们......因为它们位于错误的哈希链上。)
最安全的方法是使用不可变的密钥类。
在没有正确同步的多线程应用程序中使用映射。这可能会导致地图数据结构损坏,这可能表现为丢失的条目。
您不知道的应用程序的其他一些部分正在删除条目。
声明/声明您必须覆盖equals
并且hashcode
是/不正确的答案。在某些情况下Object
,这些方法的实现正是所需要的。您需要做的是确保:
- 您正在使用用例要求的适当形式的密钥相等,并且
- 您
equals
并hashcode
遵守“合同”。
我能做些什么来解决这个问题?
我建议进行代码检查以检查上述问题。
调试是另一种选择。例如,您可以查看是否可以在错误的哈希链上找到丢失的条目。但是,我怀疑这种方法可能有点“碰巧”。
我正在使用 weblogic 作为服务器。
不相关......除非您碰巧使用由 Weblogic 而不是 J2SE 实现的某些 Map 实现类。(查看对象的类名。)
我应该使用任何环境值吗?
不,这无济于事
一种可能的情况是:
如果 key 是类的实例并且该类没有覆盖 equals/hashcode 方法,则 get 方法可能返回 false。
如果您的密钥是可变的,那么以改变其哈希值的方式改变密钥将导致查找失败。
例如,假设您有以下可变类:
public class MyKey {
private int value;
public void setValue(int value) {
this.value = value;
}
public int hashCode() {
return value;
}
public boolean equals(Object obj) {
//...
}
}
那么这是可能的:
MyKey key = new MyKey();
key.setValue(1);
Map<MyKey, String> map = new HashMap<MyKey, String>();
map.put(key, "Hello");
System.out.println("map contains: " + map.get(key)); // "map contains: Hello"
key.setValue(2);
System.out.println("map contains: " + map.get(key)); // "map contains: "
扩展 Nambari 的答案:
如果您使用不覆盖 equals 和 hashCode 作为键的类,则相等性基于对象相等性(例如:相同的对象地址,不同的内容)。这与您不能将字符串与 == 进行比较的原因相同。
class Key {
public String k;
public Key(String k) { this.k = k; }
/*
//with this it would work.
public boolean equals(Object o) {
if (o instanceof Key) return ((Key)o).k.equals(k);
return false;
}
public int hashCode() {
return k.hashCode();
}
*/
}
map.put(new Key("a"),"test");
map.get(new Key("a")); // does NOT return "test" because key is another instance.