一个Comparator在我使用我TreeMap打破了我的意图的行为TreeMap.看下面的代码:
TreeMap<String, String> treeMap = new TreeMap<>(new Comparator<String>() {
public int compare(String o1, String o2) {
return o1.toLowerCase().compareTo(o2.toLowerCase());
}
});
treeMap.put("abc", "Element1");
treeMap.put("ABC", "Element2");
Run Code Online (Sandbox Code Playgroud)
我认为我所做的是我创建了一个按键排序的地图,不区分大小写.两个不同的元素具有不相等的键(abc和ABC),其比较将返回0.我期待这两个元素的随机排序.然而,命令:
System.out.println("treeMap: " + treeMap);
Run Code Online (Sandbox Code Playgroud)
导致:
treeMap: {abc=Element2}
Run Code Online (Sandbox Code Playgroud)
钥匙abc已重新分配价值Element2!
任何人都可以解释这是怎么发生的,如果它是一个有效的,记录在案的行为TreeMap?
And*_*ner 36
它发生是因为TreeMap认为元素相等a.compareTo(b) == 0.它在JavaDoc for TreeMap(强调我的)中有记录:
请注意,树映射维护的顺序(如任何有序映射)以及是否提供显式比较器必须与
equals此有序映射是否正确实现Map接口一致.(参见Comparable或Comparator查看与...一致的精确定义equals.)这是因为Map接口是根据equals操作定义的,但是有序映射使用其compareTo(或compare)方法执行所有键比较,因此两个被认为相等的键从排序映射的角度来看,这种方法是相同的.即使排序不一致,排序映射的行为也是明确定义的equals; 它只是不遵守Map接口的一般合同.
你的比较器与equals不一致.
如果你想保持不等于但等于忽略大小的元素,那么对你的比较器进行第二级检查,使用区分大小写的顺序:
public int compare(String o1, String o2) {
int cmp = o1.compareToIgnoreCase(o2);
if (cmp != 0) return cmp;
return o1.compareTo(o2);
}
Run Code Online (Sandbox Code Playgroud)
Era*_*ran 12
在Comparator你传递给TreeMap决定不内键的只是排序Map,这也决定两个键是否被认为是相同的(它们被认为是相同的时候compare()返回0).
因此,在你的TreeMap"abc"和"ABC"被认为是相同的键.Maps不允许使用相同的键,因此第二个值会Element2覆盖第一个值Element1.