我们遇到了一个奇怪的问题。我们获得了Oracle Coherence缓存的KeySet,但是无法直接从缓存中获取值,即使没有更新活动也是如此。
以下代码一致失败(即输出“>>>> NULL”,因为未检索到该对象)。问题是:为什么?
NamedCache nc = CacheFactory.getCache(cacheName);
Set<Object> keys = (Set<Object>)nc.keySet();
for ( Object key : keys ) {
Object o = nc.get(key);
if ( o == null ) {
System.out.println(">>>>NULL:"+keyStr);
}
}
缓存是具有多个索引的分区命名缓存。
键是一个对象(未显示),带有一个实例变量,一个HashMap。
key对象还有equals()和hashCode()方法,如下所示:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((values == null) ? 0 : values.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
System.out.println("EQUALS");
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AbstractCacheKey other = (AbstractCacheKey) obj;
if (values == null) {
if (other.values != null)
return false;
} else if (!values.equals(other.values))
return false;
return true;
}
我相信Coherence在这个配置中使用了序列化密钥对象的哈希,这会使这两个方法无关,除了我不知道前端缓存(本地JVM,关闭了localstorage)和返回缓存(存储节点JVM)。
我们的一些代码通过重建密钥,以标准顺序插入值来部分解决此问题。这个通常有效。我不明白为什么这是必要的,因为我们的hashCode()方法和Java的HashMap的hashCode()是AFAIK,对散列的迭代顺序不敏感。为什么它通常,但并不总是有效也是一个谜。
答案 0 :(得分:2)
答案(谢谢,Dimitri)是 HashMap 不保证其序列化排序,因此序列化哈希 - &gt;反序列化 - &gt; object-hash - &gt; serialize-&gt; serialized-hash 可能导致第二个序列化哈希是与第一个不同的字节流。
Java不保证在散列中进行排序,并且序列化依赖于排序。序列化可以从一个JVM到另一个JVM,甚至在同一个JVM中。由于HashMap的内部实现是典型的内存中哈希,具有N个桶,每个桶(可能通过链表)保存一组其哈希对应于桶的条目,条目被放入哈希的顺序决定(以非指定的方式)键集迭代将返回它们的顺序。相比之下, TreeMap 应该产生一致的排序,因此可能是一致的序列化。
Coherence分区缓存以序列化形式存储密钥和值,因此它们计算密钥序列化版本的哈希函数,并对序列化密钥执行相等性检查。尽管序列化流对于重构对象的目的而言是等效的,但并不保证对散列和等式检查操作的需要相同。
更复杂的是,在近缓存中,对象以反序列化的形式保存,因此使用 equals()和 hashCode()方法。< / p>
最后,Coherence建议使用其专有的POF序列化,这通常会减少序列化的大小,并直接控制序列化到被序列化的对象。