Java hashMap的内部实现

Java hashMap的内部实现,java,hashmap,Java,Hashmap,我了解hashMap的内部实现,我需要一些帮助。HashMap在Java8中使用linkedlist存储数据,它使用树数据结构。 下面是节点类构造函数,请您帮助我理解为什么节点具有密钥的哈希值 Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value;

我了解hashMap的内部实现,我需要一些帮助。HashMap在Java8中使用linkedlist存储数据,它使用树数据结构。 下面是节点类构造函数,请您帮助我理解为什么节点具有密钥的哈希值

Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
节点(int散列,K键,V值,节点下一个){
this.hash=hash;
this.key=key;
这个值=值;
this.next=next;
}

使用哈希计算元素在哈希映射中的位置。如果向HashMap添加一个键需要在每次需要处理冲突时重新计算哈希值,那么效率将极其低下。不仅如此,有些对象可能具有昂贵的哈希函数(例如,String
hashCode
遍历字符串中的每个字符)。总是希望只计算一次这样的函数,然后缓存它们以备将来使用(因为您应该为放置在映射中的对象更改hashCode/equals)

让我们考虑一个半满的哈希图(<代码> N/2 ),其中独立的元素放置在入口集中。对于添加的任何给定元素,存在

1/2
碰撞概率(最小值)。可以填充HashMap的条目数量是
n
,但是默认的加载因子是0.75,这意味着我们还有
3n/4-n/2=n/4
条目要填充。所有这些条目都必须没有散列冲突,因为我们为每次冲突节省了时间(通过缓存)。假设没有冲突的最大可能概率为
1/2
,我们可以看到在HashMap扩展之前没有冲突发生的概率为
1/2
n/4
。这意味着对于任何规模较大的HashMap(
n=29+
,其中只有0.5*29=(大约15个)键需要填充),缓存hash值有99%以上的机会节省时间


tl;dr It节省了时间,特别是当添加/查找冲突变得频繁时。

您不认为通过读取外部源而不是内部实现本身来理解它的工作原理会更容易吗?即使是一篇Wiki文章也会有很大帮助:计算散列可能会很昂贵,因此缓存它是明智的。还要注意,是否使用链表或树并不取决于Java版本(尽管可能会有内部更改),而是取决于列表的大小:短列表通常比树更容易使用,速度更快,因此大部分情况下都会得到一个列表,只有当冲突过多时才会将其转换为树(通过受保护的方法
treeifyBin(…)
),供希望阅读的人使用。