JDK类库源码分析系列3--集合类分析(7) Map&AbstractMap

419 阅读6分钟

一、Map接口

1、结构

public interface Map<K, V> {

​ 可以看到其是一个泛型接口,K -对应的key类型,V - 对应的value值类型。

2、内部接口Entry

​ 这个接口是定义在Map接口的内部的。其表示的是以哪种结构存储key-value这种数据元素,例如这里的setKey方法、setValue方法。Map接口的不同子类可以决定key-value 映射元素不同的实现方式。

3、接口方法定义

1)、size()

int size();

​ 表示此Map key-value 元素映射的个数。

2)、isEmpty()

boolean isEmpty();

​ 此Map是否为空判断,没有 key-value 映射元素。

3)、containsKey(Object key);

boolean containsKey(Object key);

​ 是否有这个key对应的映射元素。

4)、containsValue(Object value)

boolean containsValue(Object value);

​ 是否包含有这个值的 映射元素。

5)、get(Object key)

V get(Object key);

​ 根据这个key获取对应的映射元素对应的值。

6)、put(K key, V value)

V put(K key, V value);

​ 将 此key-value构成的元素元素放到Map中。如果已经有这个key对应的映射元素了,则将原来元素的value换成这个新value。

7)、remove(Object key)

V remove(Object key);

​ 移除此key对应的映射元素,同时将其的值返回。

8)、clear()

void clear();

​ 清空此Map。

9)、keySet()

Set<K> keySet();

​ 将此Map的key-value元素元素的所有key以Set集合的方式返回。

10)、values()

Collection<V> values();

​ 与上面类似,将所有的value以Collection 的形式返回,只所以这两个方法就是Key是唯一的,而Value是可以相同的。

11)、entrySet()

Set<Map.Entry<K, V>> entrySet();

​ 将Map的key-value元素元素以Set集合的方式返回。

12)、getOrDefault(Object key, V defaultValue)

default V getOrDefault(Object key, V defaultValue) {
    V v;
    return (((v = get(key)) != null) || containsKey(key))
        ? v
        : defaultValue;
}

​ 这个default在接口中实现方法是jdk8的特性,可以看到这个方法是如果能通过key获取到对应的value就将value返回,如果不能获取到对应元素就返回defaultValue这个传入的默认值(之所以用 "||" 连接get()方法与containsKey()方法是因为可以放value为null的映射元素)。

13)、putIfAbsent(K key, V value)

default V putIfAbsent(K key, V value) {
    V v = get(key);
    if (v == null) {
        v = put(key, value);
    }

    return v;
}

​ 如果不存在这个key对应的元素就调用put放到放入这个key-value元素。这样就不会将原来的value覆盖了,直接调用put方法是会将原来的value覆盖的。

14)、remove(Object key, Object value)

default boolean remove(Object key, Object value) {
    Object curValue = get(key);
    if (!Objects.equals(curValue, value) ||
        (curValue == null && !containsKey(key))) {
        return false;
    }
    remove(key);
    return true;
}

​ 移除这个key-value对应的元素(要注意是key&value都要对应相等)。

15)、replace(K key, V oldValue, V newValue)

default boolean replace(K key, V oldValue, V newValue) {
    Object curValue = get(key);
    if (!Objects.equals(curValue, oldValue) ||
        (curValue == null && !containsKey(key))) {
        return false;
    }
    put(key, newValue);
    return true;
}

​ 类似Unsafe类的CAS操作,用新的value去替换key原来的value,不过这里我们可以看到其应该是一种不是线程安全的CAS操作,因为其的get()方法与put()方法并不是原子操作。

14)、replace(K key, V value)

default V replace(K key, V value) {
    V curValue;
    if (((curValue = get(key)) != null) || containsKey(key)) {
        curValue = put(key, value);
    }
    return curValue;
}

​ 替换原来的value,如果存在此key对应的元素。

二、AbstractMap

​ AbstractMap是Map接口的基类抽象实现。

1、结构&构造方法

public abstract class AbstractMap<K,V> implements Map<K,V> {
    /**
     * Sole constructor.  (For invocation by subclass constructors, typically
     * implicit.)
     */
    protected AbstractMap() {
    }

​ 实现Map接口的抽象方法。

2、对Entry接口的实现

public static class SimpleEntry<K,V>
    implements Entry<K,V>, java.io.Serializable
{
    private final K key;
    private V value;

    public SimpleEntry(K key, V value) {
        this.key   = key;
        this.value = value;
    }

​ 可以看到其就是简单定义了两个成员变量key&value用来存需要存储的key-value 对应的 Entry元素。

3、方法

1)、entrySet()

public abstract Set<Entry<K,V>> entrySet();

​ 这个方法就是将当前Map的key-value元素以Set集合的方式返回,同时可以看到其实abstract,需要其的子类返回。

2)、size()

public int size() {
    return entrySet().size();
}

​ 这个其实就是判断set的集合的元素个数,也可以说是有多少给Entry元素。

3)、isEmpty()

public boolean isEmpty() {
    return size() == 0;
}

​ 看size是否为0。

4)、containsValue(Object value)

public boolean containsValue(Object value) {
    Iterator<Entry<K,V>> i = entrySet().iterator();
    if (value==null) {
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (e.getValue()==null)
                return true;
        }
    } else {
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (value.equals(e.getValue()))
                return true;
        }
    }
    return false;
}

​ 判断是否有这个value对应的Entry元素。这里是通过Iterator去遍历Map中的Entry元素,这里是有两个分支,一个是如果value本身就是null的话,则是判断Entry的value是否为null由此来返回true,如果不是则是调用对应Value的equals方法判断。

5)、containsKey(Object key)

public boolean containsKey(Object key) {
    Iterator<Map.Entry<K,V>> i = entrySet().iterator();
    if (key==null) {
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (e.getKey()==null)
                return true;
        }
    } else {
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (key.equals(e.getKey()))
                return true;
        }
    }
    return false;
}

​ 这里也是以迭代器去遍历,同时要注意的是,这里是能允许key也为null的情况的。

6)、get(Object key)

public V get(Object key) {
    Iterator<Entry<K,V>> i = entrySet().iterator();
    if (key==null) {
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (e.getKey()==null)
                return e.getValue();
        }
    } else {
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (key.equals(e.getKey()))
                return e.getValue();
        }
    }
    return null;
}

​ 迭代器遍历,再返回对应的value。

7)、put(K key, V value)

public V put(K key, V value) {
    throw new UnsupportedOperationException();
}

​ 需要其的子类去支持实现,其返回UnsupportedOperationException异常。

8)、remove(Object key)

public V remove(Object key) {
    Iterator<Entry<K,V>> i = entrySet().iterator();
    Entry<K,V> correctEntry = null;
    if (key==null) {
        while (correctEntry==null && i.hasNext()) {
            Entry<K,V> e = i.next();
            if (e.getKey()==null)
                correctEntry = e;
        }
    } else {
        while (correctEntry==null && i.hasNext()) {
            Entry<K,V> e = i.next();
            if (key.equals(e.getKey()))
                correctEntry = e;
        }
    }

    V oldValue = null;
    if (correctEntry !=null) {
        oldValue = correctEntry.getValue();
        i.remove();
    }
    return oldValue;
}

​ 获取key对应Entry元素的value。通过Iterator迭代器遍历,再通过key去判断获取对应的Entry,然后将该Entry的value返回同时再通过Iterator的remove方法删除此Entry。

9)、clear()

public void clear() {
    entrySet().clear();
}

​ 清空元素,直接调用的Set的clear方法。

10)、keySet&values变量

transient Set<K>        keySet;
transient Collection<V> values;

​ 这两个变量就是用来放key以及values的。

11)、keySet()

public Set<K> keySet() {
    Set<K> ks = keySet;
    if (ks == null) {
        ks = new AbstractSet<K>() {
            public Iterator<K> iterator() {
                return new Iterator<K>() {
                    private Iterator<Entry<K,V>> i = entrySet().iterator();

                    public boolean hasNext() {
                        return i.hasNext();
                    }

                    public K next() {
                        return i.next().getKey();
                    }

                    public void remove() {
                        i.remove();
                    }
                };
            }

            public int size() {
                return AbstractMap.this.size();
            }

            public boolean isEmpty() {
                return AbstractMap.this.isEmpty();
            }

            public void clear() {
                AbstractMap.this.clear();
            }

            public boolean contains(Object k) {
                return AbstractMap.this.containsKey(k);
            }
        };
        keySet = ks;
    }
    return ks;
}

​ 这个就是获取key所对应的Set集合,可以看到其的初始化是直接通过AbstractSet去创建实现了一个匿名内部类。不过可以看到其内部迭代器的实现还是使用的entrySet()这个返回的集合对应的迭代器实现。

12)、values()

public Collection<V> values() {
    Collection<V> vals = values;
    if (vals == null) {
        vals = new AbstractCollection<V>() {
            public Iterator<V> iterator() {
                return new Iterator<V>() {
                    private Iterator<Entry<K,V>> i = entrySet().iterator();

                    public boolean hasNext() {
                        return i.hasNext();
                    }

                    public V next() {
                        return i.next().getValue();
                    }

                    public void remove() {
                        i.remove();
                    }
                };
            }

            public int size() {
                return AbstractMap.this.size();
            }

            public boolean isEmpty() {
                return AbstractMap.this.isEmpty();
            }

            public void clear() {
                AbstractMap.this.clear();
            }

            public boolean contains(Object v) {
                return AbstractMap.this.containsValue(v);
            }
        };
        values = vals;
    }
    return vals;
}

​ 整体与前一个方法相似,只是这里是对AbstractCollection抽象类的实现。

13)、equals(Object o)

public boolean equals(Object o) {
    if (o == this)
        return true;

    if (!(o instanceof Map))
        return false;
    Map<?,?> m = (Map<?,?>) o;
    if (m.size() != size())
        return false;

    try {
        for (Entry<K, V> e : entrySet()) {
            K key = e.getKey();
            V value = e.getValue();
            if (value == null) {
                if (!(m.get(key) == null && m.containsKey(key)))
                    return false;
            } else {
                if (!value.equals(m.get(key)))
                    return false;
            }
        }
    } catch (ClassCastException unused) {
        return false;
    } catch (NullPointerException unused) {
        return false;
    }

    return true;
}

​ 这里AbstractMap类的equals方法的实现是有四层的。首先是通过this 相等判断(内存地址判断),再看入参是否为Map不为Map肯定是false,然后是size,之后再是遍历Entry判断。需要注意第四层判断,如果两者遍历匹配Entry的value如果为null,则是判断两者的key,不然是直接value判断。

14)、hashCode()

public int hashCode() {
    int h = 0;
    for (Entry<K, V> entry : entrySet())
        h += entry.hashCode();
    return h;
}

​ 其的hashCode是所有的Entry对应的hashCode之和。