读源码: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);
}

 

posted @ 2025-09-15 14:59  天启A  阅读(3)  评论(0)    收藏  举报