1. 程式人生 > 程式設計 >分析HashMap 的 JDK 原始碼

分析HashMap 的 JDK 原始碼

緣由:今天好友拿著下面的程式碼,問我為什麼 Map.Entry 這個介面沒有實現 getKey() 和 getValue() 方法,卻可以使用,由此,開啟了一番查閱 JDK 原始碼的旅途….

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() 方法,然後我們可以檢視 HashMap 裡 entrySet() 的原始碼

分析HashMap 的 JDK 原始碼

從原始碼可以看出,這裡的返回了一個 EntrySet 物件,但是需要注意的是這個 EntrySetHashMap 裡的一個內部類,原始碼如下:

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<?,?>) 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,-1,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 裡的一個內部類,原始碼如下:

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<?,?>)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.至此,打完收槍!

以上就是分析HashMap 的 JDK 原始碼的詳細內容,更多關於HashMap 的 JDK 原始碼的資料請關注我們其它相關文章!