HashMap方法实现简单解析
treeifyBin方法
- 功能:使用树节点替换当前哈希对应索引下标的哈希桶中的所有节点,除非表的大小太小,需要是用扩容方法替代树化节点方法
- 传入的参数:当前的节点数组,需要树化的桶的哈希值
final void treeifyBin(Node<K,V>[] tab, int hash) {
int n, index; Node<K,V> e;
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize();
else if ((e = tab[index = (n - 1) & hash]) != null) {
TreeNode<K,V> hd = null, tl = null;
do {
TreeNode<K,V> p = replacementTreeNode(e, null);
if (tl == null)
hd = p;
else {
p.prev = tl;
tl.next = p;
}
tl = p;
} while ((e = e.next) != null);
if ((tab[index] = hd) != null)to
hd.treeify(tab);
}
}
putAll方法
- 功能:使用putMapEntries方法将一个特殊的表中的映射插入到目标的表中
- 参数:一个需要特殊的表映射对象
remove方法
- 功能:调用removeNode的方法删除一个在表中存在的映射
- 参数:映射的key值
- 返回:如果存在并且删除后,返回映射的value值,否则返回Null
removeNode方法
- 功能:实现了remove以及相关的方法
- 参数:
- hash:key的哈希值
- key:key的对象
- value: 映射对应的value对象(可以为Null)
- boolean matchValue: 如果需要匹配映射对应的value对象,那么就为true
- boolean removable: 如果为false那么就不能删除其他的节点(有一点不懂)
- 返回:被删除的节点
final Node<K,V> removeNode(int hash, Object key, Object value,
boolean matchValue, boolean movable) {
Node<K,V>[] tab; Node<K,V> p; int n, index;
if ((tab = table) != null && (n = tab.length) > 0 &&
(p = tab[index = (n - 1) & hash]) != null) {
Node<K,V> node = null, e; K k; V v;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
node = p;
else if ((e = p.next) != null) {
if (p instanceof TreeNode)
node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
else {
do {
if (e.hash == hash &&
((k = e.key) == key ||
(key != null && key.equals(k)))) {
node = e;
break;
}
p = e;
} while ((e = e.next) != null);
}
}
if (node != null && (!matchValue || (v = node.value) == value ||
(value != null && value.equals(v)))) {
if (node instanceof TreeNode)
((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
else if (node == p)
tab[index] = node.next;
else
p.next = node.next;
++modCount;
--size;
afterNodeRemoval(node);
return node;
}
}
return null;
}
clear方法
- 功能:清空表
- 无参数,无返回值
public void clear() {
Node<K,V>[] tab;
modCount++;
if ((tab = table) != null && size > 0) {
size = 0;
for (int i = 0; i < tab.length; ++i)
tab[i] = null;
}
}
containsValue方法
- 功能:如果表中存在一个或者多个某个查询的值,那么返回真
- 参数:需要查询的value对象
- 返回:boolean值
public boolean containsValue(Object value) {
Node<K,V>[] tab; V v;
if ((tab = table) != null && size > 0) {
for (Node<K,V> e : tab) {
for (; e != null; e = e.next) {
if ((v = e.value) == value ||
(value != null && value.equals(v)))
return true;
}
}
}
return false;
}
keySet方法
- 功能:返回keySet内部类
- 参数:无
- 返回值:Set
- 返回对于映射表的键对象的集合形式。这个加对象集合被这个映射对象维护,因此如果改变这个映射就会影响这个集合对象,反过来改变这个集合也会影响这个映射对象。
- 当这个映射表对象在被一个迭代器遍历访问时,如果非当前迭代器对此键对象集合进行修改,那么就会导致遍历发生错误
- 这个键对象集合支持删除操作,并且能够删除键对应的映射对,但不支持add/addAll操作
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks; 返回键对象集合
}
prepareArray方法
- 功能:实现一个函数式编程的函数接口,准备一个适合大小的数组来将表转化的数组
- 参数:一个预备的数组
- 返回值:一个大小适当的预备数组
@SuppressWarnings("unchecked")
final <T> T[] prepareArray(T[] a) {
int size = this.size;
if (a.length < size) {
return (T[]) java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
}
if (a.length > size) {
a[size] = null;
}
return a;
}
keysToArray
- 功能:将映射表中的所有键对象组合为一个数组,并且返回。首先这个方法会确保传入的数组大小足够(调用prepareArray方法来确保)
- 参数:一个预备装载的数组
- 返回:一个使用所有键对象填充的数组
<T> T[] keysToArray(T[] a) {
Object[] r = a;
Node<K,V>[] tab;
int idx = 0;
if (size > 0 && (tab = table) != null) {
for (Node<K,V> e : tab) {
for (; e != null; e = e.next) {
r[idx++] = e.key;
}
}
}
return a;
}
valuesToArray
- 功能:将映射表中得所有映射得value对象组成一个数组并且返回。这个方法通过调用prepareArray方法确保数组足够大
- 参数:预备数组
- 返回:填充好的数组
- 代码和keysToValue类似,都是浅拷贝
内部类KeySet
- 继承了AbstractSet类型
- 获取大小方法,直接返回映射表中保存得映射数目
- 清除方法,同时会调用当前映射表的清除方法
- 遍历方法会产生一个KeyIterator对象
- 查找方法会调用映射表对象的containsKey方法
- 删除方法会调用映射表对象的removeNode方法
- toArray方法,调用了keysToArray方法,prepareArray方法
- forEach方法使用了函数式编程,可以传入一个Consumer(运用Consumer.accept方法);并且在forEach遍历过程前后,会检查修改版本号是否一致,否则就发生快速失败,抛出异常
public <T> T[] toArray(T[] a) {
return keysToArray(prepareArray(a));
}
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (Node<K,V> e : tab) {
for (; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
values方法
- 功能:和keySet方法类似
Values内部类
- 和KeySet内部类类似,但是不支持remove方法
小结
- 今天继续学习了一下HashMap,目前对于树化的机制还不是很清楚,但是一些基本的操作更清晰了,还有HashMap的一些设计方案和使用的注意事项也更加清晰
- 看到了函数式编程和通配符的大量应用,虽然不会写但是越来越熟悉了
- 看到了一些设计模式,对于冲突访问的快速失败是如何实现的
- 还有一些内部类的实现机制
- 练习了英语,那个view我终于明白了它的大致意思
- 对树形化的处理越来越好奇了