Map及HashMap源码分析

Map知识及HashMap源码分析

Map

特点:key-value关系映射(相当于给某一个值添加了索引),类似存储数据的还有session、redis、json等。

HashMap:

特点:key(无序,唯一)、value(无序,不唯一)。HashMap底层的实现是哈希表。

在哈希表中取出一个key值,会进行模运算,取模的模数是根据数组长度决定的。

例:在上图中数组长度为8,对key值取模运算之后得到一个0~7的数值,会根据数值存入相对应的内存空间中,若取模数值相同,则通过链表进行相连存储。

在jdk1.7时的存储结构为数组+链表;在jdk1.8后采用数组+链表+红黑树 的结构。

LinkedHashMap

特点:采用链表的数据结构,查询速度快。

TreeMap(红黑树)

特点:采用红黑树的数据结构,有序,但是没有hash快。

Set与Map有关系吗?

Map里面对应的key值就是一个Set集合。

Map中API操作:

增加:put(key,value)

查找:isEmpty(判断数组是否为空)、size(返回map的大小)、containsKey(是否包含对应的key值)、containsValue(判断是否包含对应的value值)、get(查找是否包含对应的元素,这里传入key值,找到value)

删除:clear(清空集合中的全部属性值)、remove(删除指定元素)

遍历:

通过keySet()方法转换成key的集合,之后遍历集合即可
通过values()方法将所有value值存储到一个集合中,之后遍历集合即可。
注意:在key-value映射中key可以获取到value值,但是value不能获取key值。
通过keySet()方法转换成key的集合,之后使用迭代器返回迭代器类型的集合,之后遍历集合即可。
通过调用entrySet()方法返回一个包含key-value键值对的集合(即将key和value整体当作一组值进行存储),使用迭代器遍历集合得到迭代器类型的集合,最终使用循环可以得到属性值。
注意:使用entrySet()方法的好处就是最终可以直接调用getKey()和getValue方法()获取对应值。

HashMap和HashTable的区别:

1.HashMap线程不安全,效率较高;HashTable线程安全,效率较低。

2.HashMap中key和value都可以为空,HashTable中不允许为空。

HashMap中的重要知识点:

1.Map<String,String> map = new ashMap<>();在new的时候括号中可以给一个13,但是一般不写,系统会默认赋值16。
2.为什么写成1<<4?在CPU进行计算时,是移位运算,所以使用移位符效率更高。
3.为什么是2的n次幂?
表示HashMap的最大容量:2的30次方。
加载因子:new出来的HashMap不可能每次只用16个单位长度,肯定会需要扩容。
那么在什么时候进行扩容呢?在达到数组总长*0.75后数组就会进行扩容。
例如:
起初数组长度为16,当到达12之后会扩容成32,以此类推,当达到24之后会扩容为64 ... ...
HashMap有4个构造方法,没有一个构造方法中有创建数组的具体实现, 只存在一个空的init方法 没有在堆中帮我们开辟空间。
因为在刚开始创建数组时并不知道之后是否会有数值存放,所以在最初的时候不设定值会节省内存。如果调用put()的时候一定会在内存中存放值,内存也就一定不会浪费。
当我们点击put()方法之后,发现进入的是Map接口当中,没有任何put()方法的实现。
这时,我们要去Map接口的子类中找put()方法。
table == EMPTY_TABLE中table点击
table是一个Entry类型的数组,点击Entry后发现
Entry是一个类,这个类中有四个属性:key、value、next、hash。
next:当取模值得到相同结果时,会以链表的形式连接存放地址,next中存储下一个节点的地址。
hash:key所对应的hash值。
点击EMPTY_TABLE后会发现 EMPTY_TABLE 的初始值为空。
当table== EMPTY_TABLE 时符合条件,返回执行 inflateTable(threshold); threshold 为初始化容量,可以任意设置,之后会在方法中的roundUpToPowerOf2(toSize)中进行转换。
点击进入 roundUpToPowerOf2(toSize) 方法
首先判断设置的值是否大于最大容量,再判断值是否大于一,都满足执行
Integer.highestOneBit(i:(number - 1) << 1) : 1
即不论你传入的toSize值为多少, 最终返回的都会是一个2的n次幂的数值。
当获取到capacity时,进行接下来的运算。
threshold取capacity * loadFactor和MAXIMUM_CAPACITY+1的最小值。
之后new数组进行内存的开辟,而数组的大小恰好为capacity。
接下来,方法往回返,执行
如果key值为空的话会单独调用putForNullKey()方法保证HashMap中只能有一个空值。
给key取哈希值。hash()方法的实现:
在底层hashSeed被默认赋值为0
sun包是jdk里面提供的用C语言实现的一些系统类库。
假设数组长度是16,那么索引值是从0-15的,那么最多会占用4个二进制位置。如果我有两个key值;
k1:1010 1001
k2:1100 1001
在进行取模运算时,因为后四位一样,就会存放到相同的桶中,采用链表连接, 其他的桶处于空闲状态。但是,很明显这两个key值是不一样的,这就是哈希碰撞。
解决办法:可以将key值同时右移四位,这时再进行计算时在一定程度上减少了哈希碰撞。
这个方法是计算取模完成后的存放的位置,点进去之后
假设key值为21,二进制为10101,数组长度为16,数组长度减一后数字的二进制为1111。
当10101&1111之后得到的结果为101,转换成十进制为5,即数组下标。
为什么要进行&运算而不进行取模运算? 答:与运算的效率比取模运算高很多倍。
回到最开始的第三个问题:方面一:当数组长度为2的n次幂时,数组下标一定是0~2的n次幂减一(即n个1)。在进行&运算时会保留key值的最后几位,从而快捷方便的得到索引下标,方便进行&运算。
对HashMap中的值进行遍历,判断是否可以进行添加元素
若当前值存在,则modCount++(计数器加一)。
之后进行addEntry操作,点进去后:
size:当前数组长度、threshold:数组长度*扩容因子
如果不满足,进行createEntry操作,点进去:
如果size>threshold那么要进行扩容操作。点进resize()方法中:
若之前的容量为16,当达到12时就会进行2倍扩容,那么之前的12个元素也会拿到新数组中。
1.将容量为16的table赋值为oldTable
2.得到oldTable的长度
3.if为判断当前是否超过最大长度
4.new一个新的数组,长度为原数组的2倍
5.transfer方法点进去:
6.最后的几行为计算扩容之后的数组在达到多少之后会再次进行扩容
1.将32赋值给newCapacity
2.对旧table中的元素进行遍历
3.将e.next赋值给next
4.判断是否要重新定义一个hash值,
如果要,将null赋值给 e.hash,判断是否等于e的key值,返回0,否则返回旧的元素的hash值
5.如果不需要重新定义hash值,执行indexFoe()方法判断当前元素应该插入数组中哪个位置
最后的三行即进行一个数据交换的过程(头插法:下面说)
回到最开始的第三个问题:方面二:

扩容后容器范围由0~1111变为0~11111,这S时需要重新计算hash值
而这时发现只是由原来的后4位变为后5位,多了一位
那么这时我们只需要与操作倒数第五位即可,倒数后位不需要进行操作
当为2的n次幂后不论倒数第几个二进制都为1
进行运算,当哈希值的倒数第五位为0时,&操作不会有任何变化(即新数组和旧数组下标不变)
当倒数第五位为1时,&操作将得到1,如上图,由1101变为11101(即由13变为29)

头插法:

for(Entry<K,V> e : table)
接下来进行判断值是否为空,此处假设不为空
Entry<K,V> next = e.next;
之后进行rehash和计算索引位置,这里我们假设计算的索引位置值不变
e.next = newTable[i];
newTable[i] = e;
e = next;

总结:

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值