第一篇文章传送门
第二篇文章传送门
第三篇文章传送门
第四篇文章传送门
get方法
get方法:
public V get(Object key) {
HashMap.Node e;
return (e = this.getNode(hash(key), key)) == null ? null : e.value;
}
如果e为空,那么就返回null,不然就返回e.可以看到,主要方法是getNode方法。
getNode:
final HashMap.Node<K, V> getNode(int hash, Object key) {
HashMap.Node[] tab;
HashMap.Node first;
int n;
if ((tab = this.table) != null && (n = tab.length) > 0 && (first = tab[n - 1 & hash]) != null) {
Object k;
if (first.hash == hash && ((k = first.key) == key || key != null && key.equals(k))) {
return first;
}
HashMap.Node e;
if ((e = first.next) != null) {
if (first instanceof HashMap.TreeNode) {
return ((HashMap.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;
}
table:当前hashMap的散列表
first:桶位中的头元素
n:table数组长度
e:临时node元素。
if ((tab = this.table) != null && (n = tab.length) > 0 && (first = tab[n - 1 & hash]) != null)
第一个判断条件就是判断hashMap是否为空,第二个判断条件就是表示当前位置是否为空。
if (first.hash == hash && ((k = first.key) == key || key != null && key.equals(k))) {
return first;
}
如果桶位的第一个元素的hash与key都和要查询的一致,那么就表示找到了,直接返回。
if ((e = first.next) != null)
如果有下一个,表示当前位置不止一个元素,可能为链表,也可能是红黑树。
if (first instanceof HashMap.TreeNode) {
return ((HashMap.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);
桶位形成了链表,如果链表上的第一个元素就是要查找的元素,那么就返回,不然就继续向下寻找。
remove方法
public V remove(Object key) {
HashMap.Node e;
return (e = this.removeNode(hash(key), key, (Object)null, false, true)) == null ? null : e.value;
}
其实可以看到,是和get方法有异曲同工之妙的。它调用了removeNode方法来实现删除。
removeNode方法;
final HashMap.Node<K, V> removeNode(int hash, Object key, Object value, boolean matchValue, boolean movable) {
HashMap.Node[] tab;
HashMap.Node p;
int n;
int index;
if ((tab = this.table) != null && (n = tab.length) > 0 && (p = tab[index = n - 1 & hash]) != null) {
HashMap.Node<K, V> node = null;
Object k;
if (p.hash == hash && ((k = p.key) == key || key != null && key.equals(k))) {
node = p;
} else {
HashMap.Node e;
if ((e = p.next) != null) {
if (p instanceof HashMap.TreeNode) {
node = ((HashMap.TreeNode)p).getTreeNode(hash, key);
} else {
label88: {
while(e.hash != hash || (k = e.key) != key && (key == null || !key.equals(k))) {
p = e;
if ((e = e.next) == null) {
break label88;
}
}
node = e;
}
}
}
}
Object v;
if (node != null && (!matchValue || (v = ((HashMap.Node)node).value) == value || value != null && value.equals(v))) {
if (node instanceof HashMap.TreeNode) {
((HashMap.TreeNode)node).removeTreeNode(this, tab, movable);
}
else if (node == p) {
tab[index] = ((HashMap.Node)node).next;
}
else {
p.next = ((HashMap.Node)node).next;
}
++this.modCount;
--this.size;
this.afterNodeRemoval((HashMap.Node)node);
return (HashMap.Node)node;
}
}
return null;
}
tab:引用当前hashMap中的散列表
p:当前node元素
n:表示散列表长度
index:表示寻址结果
node:查找的结果
e:当前node的下一个元素
if ((tab = this.table) != null && (n = tab.length) > 0 && (p = tab[index = n - 1 & hash]) != null)
判断hashMap不为空,并且路由的桶位是有数据的,需要进行查找操作。
if (p.hash == hash && ((k = p.key) == key || key != null && key.equals(k))) {
node = p;
}
这种是最理想的情况,当前桶位中的元素就是要删除的元素,不用向下进行寻找。
else {
HashMap.Node e;
if ((e = p.next) != null) {
/
if (p instanceof HashMap.TreeNode) {
node = ((HashMap.TreeNode)p).getTreeNode(hash, key);
}
如果当前桶位没有要删除的元素,并且后面还有元素,那么就有两种情况,链表或者红黑树。如果是红黑树,那么就执行红黑树的查找操作。
else {
label88: {
while(e.hash != hash || (k = e.key) != key && (key == null || !key.equals(k))) {
p = e;
if ((e = e.next) == null) {
break label88;
}
}
node = e;
}
}
不为红黑树的话,那么就是链表结构,按照链表的顺序一个一个向下进行寻找,知道找到hash和key都相同的节点。
删除操作:
if (node != null && (!matchValue || (v = ((HashMap.Node)node).value) == value || value != null && value.equals(v)))
如果node不为空,那么就说明按照key查找到需要删除的数据了。
if (node instanceof HashMap.TreeNode) {
((HashMap.TreeNode)node).removeTreeNode(this, tab, movable);
}
如果是红黑树,那么就走树的删除逻辑。
else if (node == p) {
tab[index] = ((HashMap.Node)node).next;
}
p==node表示第一个桶位就找到了,那么就删除。
删除方法:将下一个节点的值赋值给现在位置就可以。
else {
p.next = ((HashMap.Node)node).next;
}
这个则是剩下的最后一种情况:链表。将当前元素p的下一个元素设置成 要删除的元素node 的下一个元素。
replace方法
public V replace(K key, V value) {
HashMap.Node e;
if ((e = this.getNode(hash(key), key)) != null) {
V oldValue = e.value;
e.value = value;
this.afterNodeAccess(e);
return oldValue;
} else {
return null;
}
}
replace方法就相对简单多了,就是根据传入的key,找到对应的node节点,进行替换即可。
public boolean replace(K key, V oldValue, V newValue) {
HashMap.Node e;
Object v;
if ((e = this.getNode(hash(key), key)) == null || (v = e.value) != oldValue && (v == null || !v.equals(oldValue))) {
return false;
} else {
e.value = newValue;
this.afterNodeAccess(e);
return true;
}
}
根据key找到对应的node节点,将新的value替换老的value。getNode方法在前面已经介绍过了,这里就不再介绍了。