【发布时间】:2019-12-10 23:29:04
【问题描述】:
我已经完成了 Java 8 Hashmap 的实现,并提出了以下疑问。请帮我澄清一下:
- 我在一篇文章中读到,具有相同哈希码的节点 将作为链表添加到同一个桶中。据说新 该链表的节点将被添加到头部而不是尾部,以避免尾部遍历。 但是当我看到源代码时,新节点被添加到尾部。 对吗?
- 我没有完全理解这个变量 MIN_TREEIFY_CAPACITY。是不是经过这么多的计数,整个地图都会被转换成树(从数组到树)?
【问题讨论】:
我已经完成了 Java 8 Hashmap 的实现,并提出了以下疑问。请帮我澄清一下:
【问题讨论】:
但是当我看到源代码时,新节点被添加到尾部。对吗?
在旧版本中,它被添加到头部。但是,Java 8 中进行了许多更改。
class A {
static class SameHash {
final int n;
SameHash(int n) {
this.n = n;
}
@Override
public int hashCode() {
return 1;
}
@Override
public String toString() {
return "SameHash{" +
"n=" + n +
'}';
}
}
public static void main(String[] args) {
HashSet<SameHash> set = new HashSet<>();
for (int i = 1; i <= 4; i++)
set.add(new SameHash(i));
System.out.println(set);
}
}
打印
[SameHash{n=1}, SameHash{n=2}, SameHash{n=3}, SameHash{n=4}]
注意:键可以有不同的 hashCode,但最终可以在同一个存储桶中。
我没有完全理解这个变量 MIN_TREEIFY_CAPACITY。是不是经过这么多的计数,整个地图都会被转换成树(从数组到树)?
在此计数之后,如果键是Comparable,则桶将转换为树
【讨论】:
Peter Lawrey 关于 MIN_TREEIFY_CAPACITY 的回复是错误的。
此常量默认为 64,用于 java.util.HashMap#treeifyBin 方法,如果存储桶的大小大于 8 (TREEIFY_THRESHOLD),则会调用该方法。
在 java.util.HashMap#treeifyBin 方法中,如果哈希表大小小于 64 则整个表 RESIZED - 加倍,否则,所讨论的桶为 TREEIFIED - 桶的 DS - 链表转换为二进制树。
关键是要保持 O(1) 插入或查找 - 如果哈希表大小很小 (64),我们可以通过将其加倍轻松地调整它的大小,因此桶的范围将加倍并且会更少哈希键的冲突,每个桶的项目将更少。
如果表大小大于 64,比将哈希表大小翻倍可能代价高昂,最好将当前桶的链表转换为搜索速度更快的二叉树桶(链表搜索是O(n) 而二叉树搜索是 O(log(n))。
【讨论】: