HashMap是否使用LinkedList或Array在Java内部实现?

HashMap是否使用LinkedList或Array在Java内部实现?,java,arrays,linked-list,hashmap,hashset,Java,Arrays,Linked List,Hashmap,Hashset,如何在内部实现HashMap?我在某个地方读到它使用了LinkedList,而在其他地方它提到了数组 我试图研究HashSet的代码,发现Entry数组。那么在哪里使用了LinkedList?它基本上是这样的: this is the main array ↓ [Entry] → Entry → Entry ← here is the linked-list [Entry] [Entry] → Entry [Entry] [null ] [null ] 因此,您有一个主数组,

如何在内部实现
HashMap
?我在某个地方读到它使用了
LinkedList
,而在其他地方它提到了数组


我试图研究
HashSet
的代码,发现
Entry
数组。那么在哪里使用了
LinkedList

它基本上是这样的:

 this is the main array
   ↓
[Entry] → Entry → Entry      ← here is the linked-list
[Entry]
[Entry] → Entry
[Entry]
[null ]
[null ]
因此,您有一个主数组,其中每个索引对应于某个散列值(
mod
'ed*,对应于数组的大小)

然后,它们中的每一个都将指向具有相同哈希值的下一个条目(同样是
mod
'ed*)。这就是链表的作用


*:作为技术说明,在修改之前,但作为基本实现,只需修改即可。

每个
HashMap
都有一个数组,在该数组中,它将每个
条目按照其键的哈希代码放置在一个位置(例如
int position=Entry.getKey().hashCode()%Array.length
)。存储
条目的位置称为存储桶

如果同一个存储桶中有多个
条目
,则这些条目将合并到
链接列表
(另请参见@Dukeling的答案)。因此,bucket比喻为:每个数组索引都是一个“bucket”,您可以在其中转储所有匹配的键

为了实现随机访问所需的恒定时间性能,必须为存储桶使用数组。在一个bucket中,您必须遍历所有元素才能找到所需的键,因此您可以使用
LinkedList
,因为它更容易附加到其中(无需调整大小)


这也表明需要一个好的散列函数,因为如果所有键都只散列到几个值,那么您将得到要搜索的长链接列表和大量(快速访问)空存储桶。

HashMap有一个HashMap数组。条目对象:

/**
 * The table, resized as necessary. Length MUST Always be a power of two.
 */
transient Entry<K,V>[] table; 
/**
*表,根据需要调整大小。长度必须始终是2的幂。
*/
瞬态条目[]表;
我们可以说Entry是一个单向链表(比如HashMap.Entry链接称为“Bucket”),但它实际上不是java.util.LinkedList

你自己看看:

static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        int hash;

        /**
         * Creates new entry.
         */
        Entry(int h, K k, V v, Entry<K,V> n) {
            value = v;
            next = n;
            key = k;
            hash = h;
        }

        public final K getKey() {
            return key;
        }

        public final V getValue() {
            return value;
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry e = (Map.Entry)o;
            Object k1 = getKey();
            Object k2 = e.getKey();
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
                Object v1 = getValue();
                Object v2 = e.getValue();
                if (v1 == v2 || (v1 != null && v1.equals(v2)))
                    return true;
            }
            return false;
        }

        public final int hashCode() {
            return (key==null   ? 0 : key.hashCode()) ^
                   (value==null ? 0 : value.hashCode());
        }

        public final String toString() {
            return getKey() + "=" + getValue();
        }

        /**
         * This method is invoked whenever the value in an entry is
         * overwritten by an invocation of put(k,v) for a key k that's already
         * in the HashMap.
         */
        void recordAccess(HashMap<K,V> m) {
        }

        /**
         * This method is invoked whenever the entry is
         * removed from the table.
         */
        void recordRemoval(HashMap<K,V> m) {
        }
    }
静态类条目实现Map.Entry{
最终K键;
V值;
进入下一步;
整数散列;
/**
*创建新条目。
*/
入口(入口h、入口K、入口V、入口n){
值=v;
next=n;
key=k;
hash=h;
}
公共最终K getKey(){
返回键;
}
公共最终V getValue(){
返回值;
}
公共最终V设定值(V新值){
V oldValue=值;
值=新值;
返回旧值;
}
公共最终布尔等于(对象o){
如果(!(映射项的实例))
返回false;
Map.Entry e=(Map.Entry)o;
对象k1=getKey();
对象k2=e.getKey();
如果(k1==k2 | |(k1!=null&&k1.equals(k2))){
对象v1=getValue();
对象v2=e.getValue();
如果(v1==v2 | |(v1!=null&&v1.equals(v2)))
返回true;
}
返回false;
}
公共最终int hashCode(){
返回(key==null?0:key.hashCode())^
(value==null?0:value.hashCode());
}
公共最终字符串toString(){
返回getKey()+“=”+getValue();
}
/**
*只要输入条目中的值,就会调用此方法
*被调用put(k,v)覆盖的密钥k已经
*在HashMap中。
*/
void recordAccess(HashMap m){
}
/**
*只要输入了条目,就会调用此方法
*从表中删除。
*/
void记录删除(HashMap m){
}
}

HashMap在内部使用条目来存储键值对。条目为LinkedList类型

条目包含以下内容->

K键

V值和

Entry next>即铲斗位置上的下一个条目

静态类条目{
K键;
V值;
进入下一步;
公共输入(K键、V值、下一个输入){
this.key=key;
这个值=值;
this.next=next;
}
}
哈希映射图-


From:

当您想了解
HashMap
的实现时,为什么要查看
HashSet
HashMap
使用链接列表,但不使用类
LinkedList
。是否阅读源代码?它实际上充满了信息性的评论…@SotiriosDelimanolis我正在浏览所有集合的内部实现,学习hashset和hashmap是可以的guess@Grammin:读了这篇文章后,我感到很困惑。@Grammin我发现这篇文章竟然没有包含“链接”这个词,这让我感到惊讶。(它也有点漫无边际)面试问题的前提也有点愚蠢。“您将如何实现哈希表?”是一个很好的面试问题。“从内存中解释Java如何实现
HashTable
”是愚蠢的。当你真正关心微优化时,了解这些细节是有一定价值的,但没有理由提前记住它们。注意,自java 8以来,如果树形图太大,桶中的LinkedList可以替换为树形图。请看这里:
static class Entry<K, V> {
     K key;
     V value;
     Entry<K,V> next;

     public Entry(K key, V value, Entry<K,V> next){
         this.key = key;
         this.value = value;
         this.next = next;
     }
}