Hash底层实现原理
hashtable底层原理

hashtable底层原理Hashtable底层原理Hashtable是一种常见的数据结构,它可以快速地进行数据的查找和插入操作。
在Java中,Hashtable是一个非常常用的类,它的底层实现是基于哈希表的。
本文将从哈希表的基本原理、哈希函数的设计、哈希冲突的处理以及Hashtable的实现等方面来介绍Hashtable的底层原理。
一、哈希表的基本原理哈希表是一种基于数组的数据结构,它通过哈希函数将数据映射到数组的某个位置上。
哈希函数的设计是哈希表的关键,它决定了数据在数组中的位置。
哈希表的基本操作包括插入、查找和删除。
插入操作将数据插入到哈希表中,查找操作根据关键字查找数据,删除操作将数据从哈希表中删除。
二、哈希函数的设计哈希函数的设计是哈希表的关键,它决定了数据在数组中的位置。
哈希函数的设计需要满足以下几个条件:1. 映射范围:哈希函数需要将数据映射到数组的某个位置上,因此哈希函数的返回值需要在数组的范围内。
2. 均匀性:哈希函数需要将数据均匀地映射到数组的各个位置上,这样可以避免哈希冲突的发生。
3. 碰撞概率:哈希函数需要尽可能地减少哈希冲突的发生,这样可以提高哈希表的效率。
常见的哈希函数包括直接寻址法、除留余数法、数字分析法、平方取中法、折叠法等。
三、哈希冲突的处理哈希冲突是指不同的数据经过哈希函数映射到数组的同一个位置上。
哈希冲突的发生是不可避免的,因此需要采取一些方法来处理哈希冲突。
常见的哈希冲突处理方法包括开放地址法和链地址法。
开放地址法是指当哈希冲突发生时,继续寻找数组中的下一个空位置,直到找到为止。
链地址法是指将哈希冲突的数据存储在链表中,每个数组位置上存储一个链表头指针,指向链表的第一个节点。
四、Hashtable的实现Hashtable是Java中的一个非常常用的类,它的底层实现是基于哈希表的。
Hashtable的实现采用了链地址法来处理哈希冲突。
当哈希冲突发生时,将数据存储在链表中,每个数组位置上存储一个链表头指针,指向链表的第一个节点。
hash算法原理

hash算法原理哈希算法是一种通过输入数据生成固定长度哈希值的算法。
其原理是将任意长度的消息明文转换成固定长度的哈希值,该哈希值具有以下几个特点:1. 一致性:对于相同的输入,哈希算法始终生成相同的哈希值。
2. 高效性:哈希算法的计算速度较快,适用于处理大量的数据。
3. 不可逆性:从哈希值无法计算出原始输入数据,即无法通过哈希值还原出明文信息。
4. 雪崩效应:输入的微小改动会导致哈希值的明显改变,即输入变化一点,输出变化很大。
常见的哈希算法包括MD5、SHA-1、SHA-256等。
其中,MD5(Message-Digest Algorithm 5)是一种广泛使用的哈希算法,将输入的消息明文经过多次的数据处理和位运算,生成一个128位的哈希值。
SHA-1(Secure Hash Algorithm 1)是一种较新的哈希算法,将输入的消息明文生成一个160位的哈希值。
而SHA-256(Secure Hash Algorithm 256)则是一种更加安全的哈希算法,生成一个256位的哈希值。
哈希算法的应用场景广泛,常见的包括密码存储、数字签名、数据完整性校验等。
在密码存储中,通常将用户密码经过哈希算法处理后存储在数据库中,以保护用户的密码安全。
在数字签名中,哈希算法用于验证消息的完整性和真实性,确保消息在传输过程中没有被篡改。
在数据完整性校验中,哈希算法用于检测数据是否被篡改,例如文件下载过程中可以通过比较下载文件的哈希值和预先计算好的哈希值来判断文件是否被篡改。
总之,哈希算法通过将任意长度的消息明文转换成固定长度的哈希值,具有高效、高安全性和不可逆等特点,被广泛应用于信息安全领域。
hash算法原理

hash算法原理哈希算法(hash algorithm)是一种将输入数据转换为固定长度的输出数据的算法。
它将对不同长度的输入生成固定长度的哈希值,而且相同的输入一定会产生相同的哈希值。
哈希算法广泛应用于密码学、数据完整性校验、数据压缩和快速查找等领域。
哈希算法的原理是通过一系列复杂的计算和位运算将输入数据映射到一个固定长度的哈希值上,使得每一个输入数据都对应唯一的输出。
在哈希算法中,输入数据可以是任意长度的二进制数据,包括数字、文字、音频、视频等等。
哈希算法的基本思想是将输入数据分块处理,逐步迭代计算得到最终的哈希值。
下面是哈希算法的基本步骤:1.初始化:选择一个恰当的初始哈希值,并初始化计算环境。
2.填充数据:将输入数据按照指定规则进行填充,以保证每一块数据的长度相等。
3.分块计算:将填充后的数据按照固定大小切分为若干块,并对每一块进行特定的计算操作。
4.迭代计算:对每一块数据进行迭代计算,将上一块的哈希值与当前块的数据一起计算确定下一块的哈希值。
5.最终计算:将所有块的哈希值经过特定的合并运算,得到最终的哈希值。
哈希算法的设计考虑了以下几个重要特性:1.一致性:对于相同的输入数据,无论何时何地进行计算,都会得到相同的哈希值。
2.唯一性:不同的输入数据一定会产生不同的哈希值。
在理想情况下,不同的数据产生相同哈希值的概率应该非常小。
3.高效性:哈希算法应该具备高效的计算速度,能够快速处理大量的输入数据。
4.不可逆性:基于哈希值推导出输入数据应该是极其困难的,即使对于微小的输入数据变化也会导致哈希值变化。
5.雪崩效应:输入数据的微小变化应该能够导致哈希值的巨大变化,以此保证数据的一丁点改动都能够反映在哈希值中。
常见的哈希算法有MD5、SHA-1、SHA-256等。
其中,MD5是最常用的哈希算法之一,但是由于其漏洞和可逆性较高,现在已经不推荐使用。
SHA-1是MD5的后继者,提供了更高的安全性和更大的哈希值长度,但是也存在一些安全隐患。
hashmap底层原理及实现扰动算法,寻址算法

hashmap底层原理及实现扰动算法,寻址算法
1.HashMap底层原理:
HashMap底层使用哈希表实现,它通过键的哈希值来确定位置,存取
数据使用时间复杂度为O(1),也就是说查找,插入,删除的操作的时间
复杂度大致都是一样的。
哈希表以一种数组的方式储存,它们的每个位
置称为桶,可以使用链接结构或者红黑树结构来储存,在很多情况下只会
用到链接结构。
HashMap会根据输入的键计算出哈希值,哈希值再计算出
储存的桶的索引,最后将数据存入桶里。
2.扰动算法:
HashMap底层使用扰动算法来解决哈希冲突,扰动算法是一种在冲突
发生时,增加索引位置的算法。
也就是能不能把同一个哈希值的键储存到
不同的索引位置,以避免冲突。
HashMap使用的称为线性探测的扰动算法,它会在原来的索引位置上加上一个数,并以此来确定新的索引位置,当这
个位置也有冲突时,则继续累加,直到没有冲突或者所有位置都被检查过。
3.寻址算法:
HashMap底层哈希表采用开放定址法实现,开放定址法是一种寻址算法,它使用哈希函数计算出位置,若发生冲突时,使用某种规则在原有位
置基础上,往后移动一定长度来寻找可以插入的空间,例如HashMap底层
使用的线性探测算法就是这种方法。
哈希的实现原理

哈希的实现原理哈希(Hash)是一种常见的数据结构和算法,用于将数据快速有效地映射为确定长度的固定值。
它广泛应用于计算机科学和密码学领域,具有快速查找、数据完整性校验和数据加密等重要功能。
下面将详细介绍哈希的实现原理。
一、哈希的概念和特点哈希的概念很简单,即将不同长度的输入数据通过哈希函数(Hash Function)转换为固定长度的输出,通常称为哈希值、散列值或者摘要。
哈希的实现原理包括以下几个关键特点:1. 唯一性:对于任意输入数据,其哈希值应该是唯一的,即不同的输入应该得到不同的输出。
然而,由于输入数据的无限性,哈希函数无法保证完全唯一。
2. 确定性:对于相同的输入,哈希函数应该始终生成相同的哈希值。
3. 高效性:哈希函数应该能够快速计算出哈希值,使其适用于对大量数据进行处理。
4. 低碰撞性:碰撞指的是不同的输入数据产生相同的哈希值。
哈希函数应该尽可能降低碰撞的概率,以保证数据完整性。
二、哈希函数的种类哈希函数是哈希实现的核心,它根据输入数据的特性将其转换为哈希值。
常见的哈希函数包括以下几种:1. 散列函数(Hash Function):这是一种主要用于散列数据的哈希函数,它将数据映射为固定长度的数字。
散列函数通常具有高效计算和低碰撞的特点。
常用的散列函数有MD5、SHA-1和SHA-256等。
2. 布鲁姆过滤器(Bloom Filter):布鲁姆过滤器是一种特殊的哈希函数,它用于快速判断一个元素是否存在于一个大集合中。
布鲁姆过滤器通过将元素映射为多个比特位,并使用多个哈希函数来判断元素的存在性。
3. HMAC(Hash-based Message Authentication Code):HMAC是一种基于哈希函数的消息认证码,它通过将密钥与消息进行哈希运算,生成具有一定位数的认证码。
HMAC常用于数据完整性校验和身份验证等场景。
三、哈希冲突与解决办法由于输入数据的多样性和哈希函数的固定长度输出,哈希冲突是无法完全避免的。
java hashmap的底层原理

java hashmap的底层原理Java的HashMap是一种常用的数据结构,用于存储键值对。
它的底层实现原理是基于哈希表。
哈希表是一种以键值对存储和访问数据的数据结构。
它通过将键映射到哈希表中的一个位置来快速访问值。
在Java的HashMap中,键和值都可以为任意类型的对象。
HashMap的底层实现是一个数组,数组的每个元素称为一个桶(bucket)。
每个桶中存储了一个链表的头节点,链表中的每个节点都是一个键值对。
当插入一个键值对时,HashMap首先根据键的哈希码(hash code)计算出它在数组中的桶的位置,然后将键值对插入到该链表的头部。
在进行插入、查找或删除操作时,HashMap首先根据键的哈希码计算出它在数组中的桶的位置,然后遍历该桶的链表,找到对应的节点。
这个过程称为哈希冲突的解决,即多个键映射到同一个桶的情况。
当哈希冲突发生时,HashMap使用链表法来解决。
链表法是指在桶中使用链表来存储多个键值对,当发生哈希冲突时,新的键值对会插入到链表的头部。
这样,在查找或删除操作时,只需要遍历链表即可找到对应的节点。
然而,当链表过长时,会导致查找或删除操作的时间复杂度变高。
为了解决这个问题,Java的HashMap在链表长度达到一定阈值时,会将链表转换为红黑树。
红黑树是一种自平衡的二叉搜索树,它的插入、查找和删除操作的时间复杂度都是O(log n)。
除了链表转红黑树之外,HashMap还会在数组的长度达到一定阈值时,进行扩容操作。
扩容操作会重新计算每个键的桶位置,然后将所有节点重新插入新的桶中。
这样可以保证哈希表的装载因子在一个合理的范围内,提高HashMap的性能。
在使用HashMap时,需要注意键的类型应该正确实现hashCode()和equals()方法,以确保它们的哈希码和相等性判断是正确的。
否则,可能会导致键在哈希表中无法正确定位。
由于哈希表是无序的,遍历HashMap的键值对时,得到的顺序是不确定的。
HashSet底层原理详解

HashSet底层原理详解HashSet底层原理详解1. 说明1. HashSet实现了Set接⼝2. HashSet底层实质上是HashMap3. 可以存放null值,但是只能有⼀个null4. HashSet不保证元素是有序的,取决于hash后,再确定索引的结果,即不保证存放元素的顺序和取出顺序⼀致5. 不能有重复元素/对象2. 底层机制说明HashSet底层是HashMap,HashMap底层是(数组+链表+红⿊树)1. 先获取元素的哈希值(hashcode⽅法)2. 对哈希值进⾏运算,得出⼀个索引值即为要存放在哈希表中的位置号3. 如果该位置上没有其他元素,则直接存放,如果该位置上有其他元素,则需要进⾏equals判断,如果相等,则不再添加,如果不相等,则以链表的⽅式添加4. Java8以后,如果⼀条链表中的元素个数到达TREEIFY_THRESHOLD(默认是8),并且table的⼤⼩>=MIN_TREEIFY_CAPACITY(默认64),就会进⾏数化(红⿊树)class HashSetSource {public static void main(String[] args) {HashSet hashSet = new HashSet();//第 1 次 addhashSet.add("java");//第 2 次 addhashSet.add("php");hashSet.add("java");System.out.println("set=" + hashSet);/*** 对 HashSet 的源码解读** 1. 执⾏ HashSet()* public HashSet() {* map = new HashMap<>();* }** 2. 执⾏ add()* public boolean add(E e) {//e = "java"* return map.put(e, PRESENT)==null;* //(static) PRESENT = new Object();* }** 3.执⾏ put() , 该⽅法会执⾏ hash(key) 得到 key 对应的 hash 值* 根据算法 h = key.hashCode()) ^ (h >>> 16)* public V put(K key, V value) {//key = "java" value = PRESENT 共享* return putVal(hash(key), key, value, false, true);* }** 4.执⾏ putVal* final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {* Node<K,V>[] tab;* Node<K,V> p;* int n, i; //定义了辅助变量* //table 就是 HashMap 的⼀个数组,类型是 Node[]* //if 语句表⽰如果当前 table 是 null, 或者⼤⼩=0* //就是第⼀次扩容,到 16 个空间.* if ((tab = table) == null || (n = tab.length) == 0)* n = (tab = resize()).length;** //(1)根据 key,得到 hash 去计算该 key 应该存放到 table 表的哪个索引位置,并把这个位置的对象,赋给 p* //(2)判断 p 是否为 null* //(2.1) 如果 p 为 null, 表⽰还没有存放元素, 就创建⼀个 Node (key="java",value=PRESENT)* //(2.2) 就放在该位置 tab[i] = newNode(hash, key, value, null)* if ((p = tab[i = (n - 1) & hash]) == null)* tab[i] = newNode(hash, key, value, null);* else {** //⼀个开发技巧提⽰:在需要局部变量(辅助变量)时候,在创建** Node<K,V> e; K k;** //如果当前索引位置对应的链表的第⼀个元素和准备添加的 key 的 hash 值⼀样* //并且满⾜下⾯两个条件之⼀:** //(1) 准备加⼊的 key 和 p 指向的 Node 结点的 key 是同⼀个对象* //(2) p 指向的 Node 结点的 key 的 equals() 和准备加⼊的 key ⽐较后相同* //就不能加⼊** if (p.hash == hash &&* ((k = p.key) == key || (key != null && key.equals(k))))* e = p;** //再判断 p 是不是⼀颗红⿊树,* //如果是⼀颗红⿊树,就调⽤ putTreeVal , 来进⾏添加** else if (p instanceof TreeNode)* e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);* else {** //如果 table 对应索引位置,已经是⼀个链表, 就使⽤ for 循环⽐较** //(1) 依次和该链表的每⼀个元素⽐较后,都不相同, 则加⼊到该链表的最后* // 注意在把元素添加到链表后,⽴即判断该链表是否已经达到 8 个结点* // , 就调⽤ treeifyBin() 对当前这个链表进⾏树化(转成红⿊树)* // 注意,在转成红⿊树时,要进⾏判断, 判断条件** // if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY(64))* // resize();** // 如果上⾯条件成⽴,先 table 扩容.* // 只有上⾯条件不成⽴时,才进⾏转成红⿊树** //(2) 依次和该链表的每⼀个元素⽐较过程中,如果有相同情况,就直接 break*/}}3. 分析HashSet的扩容和转成红⿊树机制1. HashSet底层是HashMap,第⼀次添加时,table的数组扩容到16,临界值(threshold)是16 * 加载因⼦(loadFactor是0.75)=122. 如果table数组使⽤到了临界值12,就会扩容到16 * 2 = 32,新的临界值就是32 * 0.75 = 24,依次类推3. Java8以后,如果⼀条链表中的元素个数到达TREEIFY_THRESHOLD(默认是8),并且table的⼤⼩>=MIN_TREEIFY_CAPACITY(默认64),就会进⾏数化(红⿊树),否则仍然采⽤数组扩容机制。
javahashmap底层原理

javahashmap底层原理HashMap是Java中常用的集合类之一,它是基于哈希表实现的。
哈希表是一种根据键的哈希码值直接进行访问的数据结构。
它通过使用一个数组来存储键值对,数组的每个元素称为桶(bucket)。
每个桶可以存储一个或多个键值对。
HashMap使用键的哈希码值作为索引,将键值对存储在相应的桶中。
在Java的HashMap中,哈希码值是通过调用键的hashCode(方法生成的。
每个键的哈希码值是唯一的,就像每个对象的内存地址一样。
对于两个不同的键,它们可能生成相同的哈希码值,这种情况被称为哈希冲突。
当发生哈希冲突时,HashMap使用链表来解决冲突。
每个桶可以存储多个键值对,它们以链表的形式连接在一起。
在Java 8之后,当链表长度超过8时,HashMap会将链表转换为红黑树进行优化,以提高性能。
为了支持快速访问,Java的HashMap还使用了一个重要的概念:负载因子(load factor)。
负载因子是桶数组长度与实际存储元素数量之比。
当实际存储元素数量超过负载因子与桶数组长度的乘积时,HashMap会自动进行扩容操作。
当HashMap需要扩容时,它会创建一个更大的桶数组,并重新计算每个键的哈希码值,将键值对重新分布到新的桶中。
这个过程实际上是非常耗时的,因为需要重新计算哈希码值并重新分配键值对。
另外,Java的HashMap还实现了键的比较操作。
当我们使用get(方法根据键来访问值时,HashMap会首先计算键的哈希码值,然后找到对应的桶,然后使用equals(方法来比较键是否相等。
如果两个键相等,则返回对应的值,否则返回null。
总结一下,Java的HashMap底层原理可以归纳为以下几点:1.使用哈希表作为底层数据结构,通过将键的哈希码值映射到桶数组中来访问键值对。
2.当发生哈希冲突时,使用链表来解决冲突,长度超过8时会转换为红黑树。
3.使用负载因子来控制扩容操作,以提供较快的访问性能。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
HashMap的底层实现原理一、HashMap的数据结构总述:哈希的出现时因为传统数据结构如线性表(数组,链表等),树中,关键字与其它的存放位置不存在对应的关系。
因此在查找关键字的时候需要逐个比对,虽然出现了二分查找等各种提高效率的的查找算法。
但是这些并不足够,希望在查询关键字的时候不经过任何比较,一次存取便能得到所查记录。
因此,我们必须在关键字和其对应的存储位置间建立对应的关系f。
这种对应的关系f被称为哈希函数,按此思想建立的表为哈希表。
关键在于哈希函数如何构造。
意思就是:关键字的存储位置是有关键字的内容决定的。
数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端。
数组:数组存储区间是连续的,占用内存严重,故空间复杂的很大。
但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;链表:链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。
链表的特点是:寻址困难,插入和删除容易。
哈希表:那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表。
哈希表((Hash table)既满足了数据的查找方便,同时不占用太多的内容空间,使用也十分方便。
哈希表有多种不同的实现方法,我接下来解释的是最常用的一种方法——拉链法,我们可以理解为“链表的数组”一个长度为16的数组中,每个元素存储的是一个链表的头结点。
那么这些元素是按照什么样的规则存储到数组中呢。
一般情况是通过hash(key)&len-1获得,也就是元素的key的哈希值对数组长度取模得到。
HashMap其实也是一个线性的数组实现的,所以可以理解为其存储数据的容器就是一个线性数组。
这可能让我们很不解,一个线性的数组怎么实现按键值对来存取数据呢?这里HashMap有做一些处理。
首先HashMap里面实现一个静态内部类Entry,其重要的属性有key , value, next,从属性key,value我们就能很明显的看出来Entry就是HashMap键值对实现的一个基础bean,我们上面说到HashMap的基础就是一个线性数组,这个数组就是Entry[],Map里面的内容都保存在Entry[]里面。
Transient Entry[]table;二、HashMap的存取实现:// 存储时:int hash = key.hashCode();// 这个hashCode方法这里不详述,只要理解每个key的hash是一个固定的int值int index = hash % Entry[].length;Entry[index] = value;// 取值时:int hash = key.hashCode();int index = hash % Entry[].length;return Entry[index];(1)Put疑问:如果两个key通过hash%Entry[].length得到的index相同,会不会有覆盖的危险?这里HashMap里面用到链式数据结构的一个概念。
上面我们提到过Entry类里面有一个next属性,作用是指向下一个Entry。
打个比方,第一个键值对A进来,通过计算其key的hash得到的index=0,记做:Entry[0] = A。
一会后又进来一个键值对B,通过计算其index也等于0,现在怎么办?HashMap会这样做:B.next = A,Entry[0] = B,如果又进来C,index也等于0,那么C.next = B,Entry[0] = C;这样我们发现index=0的地方其实存取了A,B,C 三个键值对,他们通过next这个属性链接在一起。
所以疑问不用担心。
也就是说数组中存储的是最后插入的元素。
到这里为止,HashMap的大致实现,我们应该已经清楚了。
public V put(K key, V value) {if (key == null)return putForNullKey(value); //null总是放在数组的第一个链表中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;//如果key在链表中已存在,则替换为新valueif (e.hash == hash && ((k = e.key) == key || key.equals(k))) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}modCount++;addEntry(hash, key, value, i);return null;}void addEntry(int hash, K key, V value, int bucketIndex) {Entry<K,V> e = table[bucketIndex];table[bucketIndex] = new Entry<K,V>(hash, key, value, e); //参数e, 是Entry.next//如果size超过threshold,则扩充table大小。
再散列if (size++ >= threshold)resize(2 * table.length);}当然HashMap里面也包含一些优化方面的实现,这里也说一下。
比如:Entry[]的长度一定后,随着map里面数据的越来越长,这样同一个index的链就会很长,会不会影响性能?HashMap里面设置一个因子,随着map的size越来越大,Entry[]会以一定的规则加长长度。
(2)Getpublic 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) {Object k;if (e.hash == hash && ((k = e.key) == key || key.equals(k)))return e.value;}return null;}(3)null key 的存取null key总是存放在Entry[]数组的第一个元素。
private V putForNullKey(V value) {for (Entry<K,V> e = table[0]; e != null; e = e.next) {if (e.key == null) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}modCount++;addEntry(0, null, value, 0);return null;}private V getForNullKey() {for (Entry<K,V> e = table[0]; e != null; e = e.next) {if (e.key == null)return e.value;}return null;}(4)确定数组index:hashCode&table.length(类似取模运算)HashMap存取时,都需要计算当前key应该对应Entry[]数组哪个元素,即计算数组下标;算法如下:/*** Returns index for hash code h.*/static int indexFor(int h, int length) {return h & (length-1);}按位取并,作用上相当于取模mod或者取余%。
这意味着数组下标相同,并不表示hashCode相同。
(5)table初始大小public HashMap(int initialCapacity, float loadFactor) {.....// Find a power of 2 >= initialCapacityint capacity = 1;while (capacity < initialCapacity)capacity <<= 1;this.loadFactor = loadFactor;threshold = (int)(capacity * loadFactor);table = new Entry[capacity];init();}注意table初始大小并不是构造函数中的initialCapacity!!而是>= initialCapacity的2的n次幂!!!!三、解决Hash冲突的办法如果两个不同对象的hashCode相同,这种现象称为冲突。
开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列)再哈希法链地址法建立一个公共溢出区Java中hashmap的解决办法就是采用的链地址法。
四、再散列rehash过程当哈希表的容量超过默认容量时,必须调整table的大小。
当容量已经达到最大可能值时,那么该方法就将容量调整到Integer.MAX_VALUE返回,这时,需要创建一张新表,将原表的映射到新表中。
void resize(int newCapacity) {Entry[] oldTable = table;int oldCapacity = oldTable.length;if (oldCapacity == MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return;}Entry[] newTable = new Entry[newCapacity];transfer(newTable);table = newTable;threshold = (int)(newCapacity * loadFactor);}/*** Transfers all entries from current table to newTable.*/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;//重新计算indexint i = indexFor(e.hash, newCapacity);e.next = newT able[i];newTable[i] = e;e = next;} while (e != null);}}}HashTable和HashMap区别第一,继承不同。