读源码:map的containsValue为什么使用string[]总是false
今天遇到了一个问题,我有一个Map<String ,String[ ]>maps的数据,现在我想通过containsValue的方法判断当前map有没有具体值,
在一开始,最简单的想法是:
if(maps.containsValue("value")) { ... }
这里很明显是错误的,string和string[ ]差距还是很大的,
所以我就想办法使用了第二版:
if(maps.containsValue(new String[]{"value1","value2"})) { ... }
本以为这次string[ ]内的值是相等的,肯定没问题,结果还是出问题了。
最后无奈只能使用了get方法放弃containsValue,才完成了对应的需求
String[] value = maps.get("key");
if("value".equals(value[0])) {
...
}
那么为什么会出现这种情况呢:我查看了Map的源码,只有一个接口,然后我又看了hashMap的源码:
public boolean containsValue(Object value) { Node<K,V>[] tab; V v; if ((tab = table) != null && size > 0) { for (Node<K,V> e : tab) { for (; e != null; e = e.next) { if ((v = e.value) == value || (value != null && value.equals(v))) return true; } } } return false; }
将全局变量table赋值给了局部变量tab,通过双重循环(先循环数组再循环链表/树)判断有没有value相同的值(先判断内容再判断地址)。
在String、Integer的equals都得到了重写,他们比较的是内容而非引用。这也是为什么我们平时使用maps.contains(str)能够得到正确返回的原因。
而在String[ ]这种数组上,就出现了问题:数组类没有重写equals,这里的equals仍然是Object中的值引用比较。
为什么会有这种设计?因为java中没有给String[ ]这种数组专门设计类。
为此java提供了下面两个方法:
String[] a1 = {"1","2"};
String[] a2 = {"1","2"};
Arrays.equals(a1, a2);//true,这是浅比较,比较的是数组里每个元素的引用
String[][] a3 = {{"1"},{"2"}};
String[][] a4 = {{"1"},{"2"}};
Arrays.equals(a1, a2);//false,
Arrays.deepEquals(a3, a4);//true,这是深比较,会递归比较内容
因此,实际使用中也可以这么写:
for (String[] value : map.values()) { Arrays.equals(new String[]{"value"},value); }

浙公网安备 33010602011771号