在Java中使用长列表作为映射键
我计划使用一个映射,其中键是相当长的列表(约10/100k的小元素):在Java中使用长列表作为映射键,java,list,design-patterns,collections,map,Java,List,Design Patterns,Collections,Map,我计划使用一个映射,其中键是相当长的列表(约10/100k的小元素): Map myMap=newhashmap(); 默认的List::hashCode()实现(在AbstractList中)使用循环中所有列表元素的hashCode计算其hashCode值。另外,List::equals()方法依次比较所有列表元素,并为第一个不同的元素返回false 这一切都是有意义的,除了列表hashcode值没有被缓存(jdk6),因此每次都会重新计算,这使得这种使用模式非常低效(map经常依赖hash
Map myMap=newhashmap();
默认的List::hashCode()
实现(在AbstractList中)使用循环中所有列表元素的hashCode计算其hashCode值。另外,List::equals()
方法依次比较所有列表元素,并为第一个不同的元素返回false
这一切都是有意义的,除了列表hashcode值没有被缓存(jdk6),因此每次都会重新计算,这使得这种使用模式非常低效(map经常依赖hashcode)。equals()
的问题会少一些,因为不同的元素平均会有一个索引较低的第一个不同项,因此循环会提前中断(但必须比较相同列表中的所有元素)
我想用一个新的自定义KeyList
类封装我的列表,将hashcode值保留在缓存中以提高性能,但是:
equals()
性能问题处理这种情况是否有更好的方法?在这种情况下,列表必须是不可变的,否则
hashCode()
会随着时间的推移而改变,从而损坏哈希映射。如果列表是不可变的,则可以计算一次hashCode()
,并将其用作Long
对象中包装的键
如果您坚持使用列表界面作为键,您应该实现您提到的KeyList
。只需创建一个列表实现,该实现委托给原始列表,但重写hashCode(),以返回可在构造函数中初始化的记忆值
public abstract static class MemoizedHashCodeList<K> implements List<K>{
private final long hashCode;
private final List<K> delegate;
public MemoizedHashCodeList(List<K> delegate) {
this.delegate = delegate;
hashCode = delegate.hashCode();
}
/* Rest of the List<K> implementation */
}
public抽象静态类memorizedHashCodeList实现列表{
私有最终长哈希码;
非公开最终名单代表;
公共MemorizedHashCodeList(列表委托){
this.delegate=委托;
hashCode=delegate.hashCode();
}
/*清单的其余部分*/
}
为了加快实现速度,可以使用Google Guava的ForwardingList
类为您实现委托模式
但最重要的是,确保你的列表是不变的。不要试图通过在可变列表上进行同步来破坏代码,这是行不通的。我认为最好的解决方案是使用KeyList类。我建议将键列表类隔离到一个方法中,并让客户机代码从该方法请求列表引用。在其他任何地方,它都可以作为列表引用 假设键列表是不可变的(它们需要用作映射键),则只需在计算哈希代码时进行同步。或者甚至跳过它,复制字符串创建其哈希代码的方式
除了只有32位的标准哈希代码之外,您还可以添加一个更强大的哈希代码,该哈希代码具有非常低的冲突概率,并对其进行比较,而不是对列表进行逐个元素的比较。使用您自己的KeyList类可以覆盖equals和hashCode。我认为您需要重构代码并创建一个单独的对象用作键。您几乎可以做任何事情来创建一个唯一的键,可以将列表保留在一个数组中并使用数组索引,或者计算列表的哈希代码并将其用作键。但将大型对象保留为键是非常罕见的,我建议您不要这样做。我的列表确实是不可变的。如果我使用list hashcode值作为键,冲突的可能性太高(仅32位),因此我不能使用您的建议。即使使用大的校验和,我也不能冒发生冲突的风险。如果在任何地方都重用相同的列表对象,那么使用IdentityMap而不是HashMap。
public abstract static class MemoizedHashCodeList<K> implements List<K>{
private final long hashCode;
private final List<K> delegate;
public MemoizedHashCodeList(List<K> delegate) {
this.delegate = delegate;
hashCode = delegate.hashCode();
}
/* Rest of the List<K> implementation */
}