`

HashMap实现原理及实现解析

 
阅读更多

java中常用到HashMap,决定了解其实现原理。

1、存储结构


1.1、数组

存储空间连续,空间复杂度大,但查询时时间复杂度小,为O(1)。即寻址容易,插入、删除困难。

1.2、链表

存储空间可以不连续,空间复杂度小,但查询时间复杂度大,为O(n)。即插入、删除容易,寻址困难。

1.3、哈希表

将数组和链表结合,取长补短,产生一种寻址容易,插入删除也容易的数据结构。



 在HashMap中有静态内部类Entry,主要结构是key、value和next,形成一个链表结构。在HashMap中有定义 transient Entry[] table来存储Entry。这样HashMap用线性数组来存储数据,根据hash值来创建Entry链。

2、存取原理

 

2.1、put

 

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());//计算用来计算存储位置的值
        int i = indexFor(hash, table.length);//计算存储位置的下标
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//key相同时替换原来的value
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;//结构改变次数,与fail-fast机制有关
        addEntry(hash, key, value, i);//构造Entry并存储
        return null;
    }

 

 void addEntry(int hash, K key, V value, int bucketIndex) {
	Entry<K,V> e = table[bucketIndex];//取出原来存储在bucketIndex位置的Entry e
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);//创建新的Entry,并将next设置为e
        if (size++ >= threshold)//当前数量达到需要扩容的门槛
            resize(2 * table.length);//重新计算容量
    }
 

 

2.2、get

 

 public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());//计算用来计算存储位置的值
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {//获取目标Entry的位置Entry链,并遍历改Entry链查找目标Entry
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;//找到目标返回
        }
        return null;
    }
 

 

2.3、remove

 

public V remove(Object key) {
        Entry<K,V> e = removeEntryForKey(key);//删除对应的Entry
        return (e == null ? null : e.value);//返回对应Entry的Value
    }

final Entry<K,V> removeEntryForKey(Object key) {
        int hash = (key == null) ? 0 : hash(key.hashCode());
        int i = indexFor(hash, table.length);
        Entry<K,V> prev = table[i];//找到对应Entry的存储链上的第一Entry
        Entry<K,V> e = prev;//e表示当前Entry

        while (e != null) {
            Entry<K,V> next = e.next;//找到e的下一个Entry标记为next
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k)))) {//发现e是要删除的Entry
                modCount++;//标记结构改变次数
                size--;//容量减一
                if (prev == e)//e是前一个Entry
                    table[i] = next;
                else
                    prev.next = next;//前一个Entry的next设为next
                e.recordRemoval(this);
                return e;//返回被删除的Entry
            }
            prev = e;//当前的Entry变成前一个Entry
            e = next;//下一个Entry变成当前的,继续判断e是否是要被删除的Entry
        }

        return e;
    }

 

3、rehash过程

 

 void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {//原数组容量已达到可用容量的上限
            threshold = Integer.MAX_VALUE;//阈值设为最大的int
            return;
        }

        Entry[] newTable = new Entry[newCapacity];
        transfer(newTable);//将原来的数组中的内容重新计算放在新的数组
        table = newTable;
        threshold = (int)(newCapacity * loadFactor);//重新设置阈值,loadFactor默认是0.75,一般不需要改变
    }

 void transfer(Entry[] newTable) {
        Entry[] src = table;
        int newCapacity = newTable.length;
        for (int j = 0; j < src.length; j++) {
            Entry<K,V> e = src[j];
            if (e != null) {
                src[j] = null;
                do {
                    Entry<K,V> next = e.next;
                    int i = indexFor(e.hash, newCapacity);
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                } while (e != null);
            }
        }
    }

 所以,如果事先知道要存储数量的大小,可预先设置好容器的大小(默认是16),减少resize的调用,以提高速度。

  • 大小: 3.5 KB
分享到:
评论

相关推荐

    hashmap实现原理

    在深入探讨HashMap的实现原理之前,我们需要了解两个关键的接口方法:`hashCode()`和`equals()`。 根据《Effective JAVA》的建议,当重写`equals()`方法时,也应重写`hashCode()`方法。这是因为在HashMap中,`...

    基于HashMap的用户标签处理兼Java中HashMap实现原理研究.pdf

    "基于HashMap的用户标签处理兼Java中HashMap实现原理研究" 本文研究了基于HashMap的用户标签处理方法,并对Java中HashMap的实现原理进行了深入研究。HashMap是一种高效的数据结构,可以快速地存储和检索数据。本文...

    java HashMap原理分析

    Java HashMap原理分析 Java HashMap是一种基于哈希表的数据结构,它的存储原理是通过将Key-Value对存储在一个数组中,每个数组元素是一个链表,链表中的每个元素是一个Entry对象,Entry对象包含了Key、Value和指向...

    Java8 HashMap的实现原理分析

    Java8之后新增挺多新东西,接下来通过本文给大家介绍Java8 HashMap的实现原理分析,对java8 hashmap实现原理相关知识感兴趣的朋友一起学习吧

    HashMap的实现原理

    ### HashMap的实现原理 #### 1. HashMap概述 HashMap 是 Java 集合框架中一个非常重要的类,它实现了 Map 接口,并提供了基于哈希表的存储方式。与其它 Map 实现不同的是,HashMap 允许使用 `null` 键和 `null` 值...

    深入解析java HashMap实现原理

    综上所述,理解HashMap的实现原理对于优化Java程序性能至关重要,尤其是在处理大量数据或并发场景时。在实际应用中,应根据具体需求选择合适的数据结构,例如,如果需要线程安全,可以选择ConcurrentHashMap;如果对...

    一线大厂BATJ面试题讲解-hashmap原理实现

    一线大厂BATJ面试题讲解-hashmap原理实现

    源码解析jdk8.0集合:HashMap的底层实现原理.pdf

    根据提供的文件信息,以下是对JDK 8.0中HashMap实现原理的详细知识点介绍: 1. HashMap概述 HashMap是Java集合框架的一部分,它实现了Map接口,用于存储键值对。其核心特点在于基于哈希表的映射机制,能够通过键...

    详解Java HashMap实现原理

    以下是对HashMap实现原理的详细解析。 首先,HashMap内部使用了一个瞬时变量数组`table`(也称为“桶”)来存储键值对。桶是一个Entry对象数组,它的大小可以动态调整,并且长度必须是2的幂。初始时,`table`是一个...

    电话本管理系统HashMap实现

    在这个系统中,使用HashMap实现是一种高效且灵活的方法,因为HashMap提供了快速的查找和插入操作。本文将深入探讨如何使用HashMap来构建一个电话本管理系统,并通过源码分析增强理解。 HashMap是Java集合框架中的一...

    源码解析jdk7.0集合(3):HashMap的底层实现原理.pdf

    ### JDK 7.0集合系列解析之HashMap实现原理 #### 一、HashMap概述 HashMap是Java集合框架中Map接口的典型实现之一,主要用于存储键值对(Key-Value)数据。其特性如下: - 线程不安全,方法为非同步方法,因此多...

    学习笔记:三数组实现的HashMap

    "学习笔记:三数组实现的HashMap"这篇博客文章可能讨论了一种非标准但有趣的HashMap实现,使用了三个数组来代替标准的哈希表结构。这里我们将深入探讨这种三数组实现HashMap的原理和可能的优势。 1. **基本概念**:...

    HashMap原理.rar

    本文将深入解析HashMap的工作原理、内部结构以及相关操作。 首先,哈希表是一种数据结构,它通过哈希函数将键(Key)映射到数组的索引位置,从而实现快速访问。HashMap在Java中是线程非同步的,适用于多线程环境下...

    hashmap面试题_hashmap_

    答:在多线程环境下,可以使用ConcurrentHashMap,它是线程安全的HashMap实现。 五、HashMap与HashSet的关系 HashSet基于HashMap实现,每个元素作为HashMap的一个键,值为null。因此,HashSet的操作性能也依赖于...

    Java HashMap实现原理分析(一)

    HashMap的实现原理基于哈希表,它的核心是通过哈希函数将键(key)映射到一个数组的特定位置,从而实现快速访问。本文将深入解析HashMap的put和get操作的内部机制。 首先,HashMap的底层数据结构是一个动态扩容的...

    面试必考之HashMap源码分析与实现

    面试中,HashMap的源码分析与实现是一个常见的考察点,因为它涉及到数据结构、并发处理和性能优化等多个核心领域。本篇文章将深入探讨HashMap的内部工作原理、关键特性以及其在实际应用中的考量因素。 HashMap基于...

    HashMap类

    HashMap类在Java编程...在阅读《HashMap1.js》和《HashMap.js》这两个文件时,可以深入分析其JavaScript版本的HashMap实现,虽然与Java版本可能有所不同,但基本的哈希映射原理是相通的,有助于拓宽对哈希表的理解。

    HashMap源码分析

    HashMap 的核心原理是将键(key)通过哈希函数转化为数组索引,然后将键值对(key-value pair)存储在数组的对应位置。如果多个键经过哈希计算得到相同的索引,HashMap 利用链表处理这种哈希冲突,形成链式存储。 ...

Global site tag (gtag.js) - Google Analytics