我遇到了一些非常怪异的TreeMap行为,我在缩小测试用例方面遇到了一些麻烦,所以请耐心等待。
我想从运行时提供的文件中将大量键值对读入Map。我正在使用自定义密钥类。后来,当我把条目撤回时,我发现其中一个或多个丢失了。使用调试器和一些测试用例,我已经确定缺少的条目在读取阶段肯定会消失,但我不确定是什么导致它。
基本上:
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
...基本上,向地图添加一个全新的密钥会导致不相关的条目失效。
我最初使用的是TreeMap,因为我希望使用大型数据集,而TreeMap的内存效率要高一些。 HashMap将是一个很好的选择,但看到TreeMap以这种方式运行仍然令人担忧 - 任何人都对这里发生的事情有所了解?
答案 0 :(得分:12)
TreeMap认为两个条目相等,如果比较时,结果为0.因此,如果key1和keyN'与'0'比较,则key1将被putN()覆盖。这是真的即使 !key1.equals(keyN)
。因此,虽然您可能认为这两个键不相等,因此插入一个不应该覆盖另一个,如果您的equals和比较函数彼此不一致,TreeMap
会认为不同。
请注意,此行为可能会因地图中元素的数量而有所不同,因为它取决于实际比较两个比较方法评估为0的元素。基本上,事情会像你说的那样“诡异”。
... map使用compareTo(或比较)执行所有关键比较 方法,所以这两种方法被认为是相同的,来自 有序地图的立场,等于......
来自Comparable javadocs(感谢@Brian):
强烈建议(尽管不要求)自然 排序与平等一致。这是因为排序集 没有显式比较器的(和排序的地图)表现得“奇怪” 它们与自然顺序的元素(或键)一起使用 与equals不一致。特别是,这样的排序集(或排序的 map)违反了定义的集合(或映射)的一般合同 就平等方法而言。
答案 1 :(得分:1)
向我们展示MyKey
的代码。我的猜测是你的compareTo
方法有问题。更具体地说,您的compareTo
与equals
不一致。
答案 2 :(得分:0)
您确定keyN在任何情况下都没有覆盖key1吗?因为在我看来那是你的幻影案例。