HashMap 的 JDK 源码探索

缘由:今天好友拿着下面的代码,问我为什么Map.Entry 这个接口没有实现 getKey() 和 getValue() 方法,却可以使用,由此,开启了一番查阅 JDK 源码的旅途….

1
2
3
4
5
6
7
8
9
10
11
12
13
Map map = new HashMap();
map.put(1, "张三");
map.put(2, "李四");
map.put(3, "王五");
map.put(4, "赵六");
map.put(5, "钱七");
Set set = map.entrySet();
for (Object object : set) {
Map.Entry entry = (Map.Entry) object;
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
  1. 首先,我们看 map 对象,这个 map 对象是 HashMap 的一个实例,然后下面的 Set set = map.entrySet(); 可以知道这其实用的 HashMap 实现的 entrySet() 方法,然后我们可以查看 HashMapentrySet() 的源码

    从源码可以看出,这里的返回了一个 EntrySet 对象,但是需要注意的是这个 EntrySetHashMap 里的一个内部类,源码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    public final int size() {
    return size;
    }
    public final void clear() {
    HashMap.this.clear();
    }
    public final Iterator<Map.Entry<K,V>> iterator() {
    return new EntryIterator();
    }
    public final boolean contains(Object o) {
    if (!(o instanceof Map.Entry))
    return false;
    Map.Entry<?,?> e = (Map.Entry<?,?>) o;
    Object key = e.getKey();
    Node<K,V> candidate = getNode(hash(key), key);
    return candidate != null && candidate.equals(e);
    }
    public final boolean remove(Object o) {
    if (o instanceof Map.Entry) {
    Map.Entry<?,?> e = (Map.Entry<?,?>) o;
    Object key = e.getKey();
    Object value = e.getValue();
    return removeNode(hash(key), key, value, true, true) != null;
    }
    return false;
    }
    public final Spliterator<Map.Entry<K,V>> spliterator() {
    return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
    }
    public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
    Node<K,V>[] tab;
    if (action == null)
    throw new NullPointerException();
    if (size > 0 && (tab = table) != null) {
    int mc = modCount;
    for (int i = 0; i < tab.length; ++i) {
    for (Node<K,V> e = tab[i]; e != null; e = e.next)
    action.accept(e);
    }
    if (modCount != mc)
    throw new ConcurrentModificationException();
    }
    }
    }

    从这里我们是可以看出,这个 EntrySet 其实是封装的一个 Node 类的实体。也就是说我们的 set 其实就是这个 Node 对象。

  2. 现在我们来说说这个 Node 对象,Node 对象也是 HashMap 里的一个内部类,源码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
    Node(int hash, K key, V value, Node<K,V> next) {
    this.hash = hash;
    this.key = key;
    this.value = value;
    this.next = next;
    }
    public final K getKey() {
    return key;
    }
    public final V getValue() {
    return value;
    }
    public final String toString() {
    return key + "=" + value;
    }
    public final int hashCode() {
    return Objects.hashCode(key) ^ Objects.hashCode(value);
    }
    public final V setValue(V newValue) {
    V oldValue = value;
    value = newValue;
    return oldValue;
    }
    public final boolean equals(Object o) {
    if (o == this)
    return true;
    if (o instanceof Map.Entry) {
    Map.Entry<?,?> e = (Map.Entry<?,?>)o;
    if (Objects.equals(key, e.getKey()) &&
    Objects.equals(value, e.getValue()))
    return true;
    }
    return false;
    }
    }

    可以看出来,这个 Node 对象是 Map.Entry<K,V> 的实现类,我们可以看到这个 Node 对象实现了 getKey()getValue() 的方法,所以后面调用的 entry.getKey() 以及 entry.getValue() 方法其实都是调用的 Node 对象里的getKey()getValue() 方法,这里就是 Java 的多态的一种表现。

  3. 至此,打完收枪!

o(╯□╰)o我只要一毛钱的鼓励~~