ConcurrentHashMap和HashMap的containsKey方法区别

一、背景

以null为key调用ConcurrentHashMap的containsKey方法时报空指针错误。

java.lang.NullPointerException
    at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
    at java.util.concurrent.ConcurrentHashMap.containsKey(ConcurrentHashMap.java:964)

二、ConcurrentHashMap和HashMap的containsKey方法区别

Map接口中containsKey方法定义如下:

public interface Map {
...
    boolean containsKey(Object key);
...
}

containsKey方法接受一个Object类型的参数,因此所有类型的对象都可以作为containsKey方法的参数,甚至null,编译不会报错。但当Map接口的实现类中containsKey方法不接受null作为入参时,以null作为入参调用该方法将抛出NullPointerException。

ConcurrentHashMap和HashMap都实现了Map接口。ConcurrentHashMap中的containsKey方法如下:

...
    public boolean containsKey(Object key) {
        return get(key) != null;
    }

    public V get(Object key) {
        Node[] tab; Node e, p; int n, eh; K ek;
        int h = spread(key.hashCode());   // key not null
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (e = tabAt(tab, (n - 1) & h)) != null) {
            if ((eh = e.hash) == h) {
                if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                    return e.val;
            }
            else if (eh < 0)
                return (p = e.find(h, key)) != null ? p.val : null;
            while ((e = e.next) != null) {
                if (e.hash == h &&
                    ((ek = e.key) == key || (ek != null && key.equals(ek))))
                    return e.val;
            }
        }
        return null;
    }

...

ConcurrentHashMap在调用containsKey方法时,会首取key的hashCode值,如果key为空,则会抛出NullPointerException。因此ConcurrentHashMap不能以null作为key

HashMap中的containsKey方法如下:

...
    public boolean containsKey(Object key) {
        return getNode(hash(key), key) != null;
    }

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }    

    final Node getNode(int hash, Object key) {
        Node[] tab; Node first, e; int n; K k;
        // key can be null
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }    
...

HashMap中定义了hash方法,该方法入参为null时返回0。因此HashMap可以null作为key。HashMap是在put元素后分配空间,HashMap刚初始化时实际没有分配存储空间,当table为空时containsKey方法将直接返回null。

三、结论

ConcurrentHashMap不能以null作为key,key为null时将返回NullPointerException;HashMap可用null作为key,key为null时,返回hash值为0指向位置的值。

你可能感兴趣的:(问题)