1、发现问题:
LinkedCaseInsensitiveMap在put值时候出现顺序问题。
public static void main(String[] args) {
LinkedCaseInsensitiveMap<Object> map = new LinkedCaseInsensitiveMap<>();
map.put("aa", 1);
map.put("bb", 2);
map.put("cc", 3);
map.put("dd", 4);
map.put("ee", 5);
map.put("CC", 333);
map.forEach((a, b) -> {
System.out.println(b);
});
//output:
//1
//2
//4
//5
//333
}
解析源码
所在包:
package org.springframework.util;
@Override
@Nullable
public V put(String key, @Nullable V value) {
String oldKey = this.caseInsensitiveKeys.put(convertKey(key), key);
V oldKeyValue = null;
if (oldKey != null && !oldKey.equals(key)) {
oldKeyValue = this.targetMap.remove(oldKey);
}
V oldValue = this.targetMap.put(key, value);
return (oldKeyValue != null ? oldKeyValue : oldValue);
}
@Override
@Nullable
public V get(Object key) {
if (key instanceof String) {
String caseInsensitiveKey = this.caseInsensitiveKeys.get(convertKey((String) key));
if (caseInsensitiveKey != null) {
return this.targetMap.get(caseInsensitiveKey);
}
}
return null;
}
protected String convertKey(String key) {
return key.toLowerCase(getLocale());
}
结论:
LinkedCaseInsensitiveMap它维护了一个LinkedHashMap(targetMap)和一个HashMap(caseInsensitiveKeys),caseInsensitiveKeys里面存储着小写->大写的映射关系,然后按照Hashmap的逻辑放到HashMap,所以当存的是CC,又把cc的值放进去时,caseInsensitiveKeys会替换值由 cc->CC 变成 cc -> cc , targetMap会把key 为CC的值去掉,然后把cc放进去,这时候会重新计算hash值去确定索引位置。