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()调用不一定与新键一起发生,而是作为树重新平衡的一部分。谢谢