本文基於JDK1.8
1. 註釋翻譯
/**
* Returns the value to which the specified key is mapped,
* or {@code null} if this map contains no mapping for the key.
* 返回指定的key映射的值value,如果此映射不包含key鍵的一射,則返回null。
* <p>More formally, if this map contains a mapping from a key
* {@code k} to a value {@code v} such that {@code (key==null ? k==null :
* key.equals(k))}, then this method returns {@code v}; otherwise
* it returns {@code null}. (There can be at most one such mapping.)
* 更正式的說,如果此映射包含從鍵key到值value的映射,那麼執行(key==null ? k==null :
* key.equals(k))操作,然後此方法返回返回值value,否則返回null。(最多可以有一個這樣的映射。)
* <p>A return value of {@code null} does not <i>necessarily</i>
* indicate that the map contains no mapping for the key; it's also
* possible that the map explicitly maps the key to {@code null}.
* The {@link #containsKey containsKey} operation may be used to
* distinguish these two cases.
* 返回null不代表地圖中不包含該key鍵的映射;有可能這個地圖中,將key鍵映射的值value爲null。containsKey操作可用於區分這兩種情況。
*
* @see #put(Object, Object)
*/
從上面的註釋我們大概的瞭解到了,get()方法的作用查找哈希表中對應key鍵的value值,如果所對應的key鍵在map中有映射的value值,則返回value值,否則返回null。
當get()方法返回爲null時,有一個特殊的情況,那就是key映射到map中的value值本身就爲空。在本方法中無法區分它們,但是在containsKey方法中可以區分它們。
2. 源碼剖析
public V get(Object key) {
Node<K,V> e;
// 在這裏執行getNode操作,要了解這裏的具體操作我們需要先看一下getNode方法,我們在下面分析一下這個方法。
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
getNode方法
/**
* Implements Map.get and related methods
* 實現Map.get和相關方法
* @param hash hash for key
* @param key the key
* @return the node, or null if none
*/
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
// 哈希表已經初始化,且分的桶的頭節點不爲空
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
// 要查找結點的key值等於桶中頭節點的key值,直接返回頭節點
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<K,V>)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;
}
我們通過源碼分析可以發現,get()方法的核心是調用了getNode()方法,getNode()方法,返回了key鍵所在的結點,如果沒有則返回null,get()方法對該值進行判斷,然後取出value進行操作。
3. get()執行流程
- 若哈希表已經初始化並且桶的首結點不爲空
① 查找結點的key值恰好等於首結點的key值,直接返回首結點。
② 進行桶中元素的遍歷,查找指定結點
a. 若樹化,按照樹的方法查找指定結點
b. 按照鏈表方式查找 - 哈希表爲空或桶的首結點爲null,直接返回null。
4. containsKey(Object key)
/**
* Returns <tt>true</tt> if this map contains a mapping for the
* specified key.
* 如果此映射包含指定key鍵的映射,則返回true
*
* @param key The key whose presence in this map is to be tested
* @return <tt>true</tt> if this map contains a mapping for the specified
* key.
*/
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
該方法也是調用了getNode方法,在這裏方法的作用時,判斷該key值在map中是否含有映射關係,如果含有映射關係,則返回true,狗則返回false。