Java TreeMap put()以静默方式删除其他条目?
我经历过一些非常可怕的树形图行为,我在缩小一个小测试用例的范围方面遇到了一些困难,所以请容忍我 我想从运行时提供的文件中将大量键值对读入映射。我正在使用自定义密钥类。稍后,当我将条目拉回来时,我发现其中一个或多个条目丢失了。通过使用调试器和一些测试用例,我确定丢失的条目在读取阶段肯定会消失,但我不确定是什么导致了它 基本上:Java TreeMap put()以静默方式删除其他条目?,java,map,key,treemap,comparable,Java,Map,Key,Treemap,Comparable,我经历过一些非常可怕的树形图行为,我在缩小一个小测试用例的范围方面遇到了一些困难,所以请容忍我 我想从运行时提供的文件中将大量键值对读入映射。我正在使用自定义密钥类。稍后,当我将条目拉回来时,我发现其中一个或多个条目丢失了。通过使用调试器和一些测试用例,我确定丢失的条目在读取阶段肯定会消失,但我不确定是什么导致了它 基本上: Map<MyKey,Double> map = new TreeMap<MyKey,Double>(); map.put(key1,value1);
Map<MyKey,Double> map = new TreeMap<MyKey,Double>();
map.put(key1,value1);
// ... put another ~500 entries into the map ...
assertTrue(map.containsKey(key1)); // passes
if (!map.containsKey(keyN)) {
map.put(keyN, valueN); // this code executes
}
assertTrue(map.containsKey(key1)); // FAILS
Map Map=newtreemap();
映射放置(键1,值1);
// ... 将另外约500个条目放入地图中。。。
assertTrue(map.containsKey(键1));//通行证
如果(!map.containsKey(keyN)){
map.put(keyN,valueN);//执行此代码
}
assertTrue(map.containsKey(键1));//失败
…因此,本质上,向地图添加一个全新的键会导致一个不相关的条目从地图中消失
- 如果我只添加key1和keyN,那么key1仍保留在映射中——中间的500个条目在某种程度上是重要的
- 如果我从2..(N-1)中删除一个或两个任意键,则添加keyN时,key1仍会被引导出
- 如果我从2..(N-1)中删除一大范围的关键点,则添加关键点N时,关键点1仍然保留,但添加(比如)关键点q时,关键点1会消失,再往下移动大约300个关键点
- 不幸的是,当keyN踢出key1时,地图的大小与keyQ踢出key1时地图的大小不一致,因此这可能不是一个大小受限的问题
- 如果改用HashMap,则key1仍保留在映射中
- 自定义密钥类MyKey对Comparable、equals和hashCode使用相同的逻辑
我最初使用TreeMap是因为我希望使用大型数据集,TreeMap的内存效率更高一些。HashMap将是一个不错的选择,但看到TreeMap以这种方式运行仍然令人担忧——有人对这里发生的事情有想法吗?您确定keyN在任何情况下都不会覆盖key1吗?因为在我看来,那是你的幻影盒。给我们看看
MyKey
的代码。我的猜测是,您的compareTo
方法有问题。更具体地说,您的比较到
与等于
树不一致。如果比较结果为0,则树映射认为两个条目相等。因此,如果key1和keyN'与'0'比较,则key1将被keyN put()覆盖。这是真的,即使!key1.equals(keyN)
。因此,虽然您可能认为这两个键不相等,因此插入一个键不应覆盖另一个键,但如果相等和比较函数不一致,则树映射将认为不同
请注意,此行为可能因映射中的元素数量而异,因为它取决于实际比较两个元素,而比较方法的计算结果为0。基本上,事情会像你所说的那样“令人毛骨悚然”
从:
…映射使用其compareTo(或compare)执行所有键比较
方法,因此此方法认为相等的两个键
排序地图的立场,相等
来自(谢谢@Brian):
强烈建议(尽管不是必需的)自然
排列顺序必须与等号一致。这是因为排序集
没有显式比较器的(和排序贴图)在
它们与自然顺序为的元素(或键)一起使用
与平等不一致。特别是这样一个排序集(或排序集)
map)违反了已定义的set(或map)总合同
根据equals方法
同意郭先生的观点。注释掉您的compareTo/equals/hashCode实现,再次运行测试,看看是否会遇到同样的问题。+1这就是为什么javadocs中有compareTo
一致性子句的原因:“强烈建议(尽管不是必需的)自然排序与equals一致。这是因为排序集(和排序映射)是一致的如果没有显式的比较器,当它们与自然顺序与equals不一致的元素(或键)一起使用时,它们的行为会“奇怪”。()是的,就是这样——我缺少的是,踢出key1的实际compareTo()调用不一定与新键一起发生,而是作为树重新平衡的一部分。谢谢