Map接口(用HashMap演示)

Java的集合类主要分为两大类:

Collectiona和Map   ,单列集合和双列集合。Collection接口中包含两类主要接口List接口和Set接口,他们两个可口下又包含很对实现类。Map接口的层级是和Collection一样的。我们来看看他的继承树

其实单列表和双列表的底层是差不多的,我的理解是单列表能一个引用,双列表放两个引用。不要拘泥于key和value是啥关系,灵活的看成两个引用变量,只不过key和value多成映射关系仅此而已。

Map接口中的底层添加元素还是通过转变key哈希值来决定存放的位置的只不过他后面会跟着value值,注意value不会和key一起计算哈希值,他只会计算key的哈希值。

我们来看张图:

前面我们说的单列表中的Set接口的时候key是不能重复的否则存不进去,而map他不是存不进去而是把你原来那个给替换了。但是我这个value是可以重复的,只要你的key不重复他就不会把相同的value替换掉比如

我这个张三丰是可以存进去的。

接着我们来看看他的底层是如何存放这个key和value的

也就是说你的这个key和value你传过来的时候会放在一个node结点中,一对键值对对应底层对应一个node结点,注意node与node之间本身不存在数组+链表的形式存在,他是通过在创建一个集合Entry,我先说这个集合Entry里面有啥东西,有属性key、value、next指针、entrySet方法,Entry集合放Entry类的对象,然后因为每一个Entry类的对象中都包含有属性key、value、next指针、entrySet方法。在Entry集合中,每一个Entry(key,value)都是通过key和value都是指向node中的键值对,由此来就对应了一个Entry对象对应一个node结点,而不是真正的存储node,每一个Entry对象里面还有一个next指针用来指向下一个Entry对象,也就是说多个Entry集合存放多个Entry对象,这多个Entry对象存放的形式就是数组+链表+红黑树。

接着说说Map的遍历方法

首先我们要知道Map遍历肯定是通过Entry这个集合来遍历的,来看一张图

在之前我们说过Collection可以用迭代器和增强for循环来遍历,但是这里面的Map就不存在迭代器这个东西了。但是我们看上面这张图,从上面的右边的那个Entry中我们可以看到Entry中的key引用他是用Set的方式存储的,然后value引用他是用Collection的方式存储的,整个entry集合用Set的方式存储的,对应的我们只要拿到所有的value,那么这所有的value就是可以调用构造器了。其他的也是一样的,先得到全部的value或entry,我们就可以调用迭代器了。上面这些刚好对应下面三个方法

 //注意一定要先用Object来接收一下key,否则你在调用map.get();方法的时候他会报错的,因为在

 map.get();要求你传入的是一个Object key;而你如果这样map.get( iterator.next() );这样做的话是传入一个Iterator类型的Object。

当然也可以用增强for循环

//这里面取得的所有key就不需要在转换了,因为在循环条件for(Object objkey : keyset)中就帮你做了转换了 。

运行结果

当然也可以用增强for

总结:其实总的来看增for会跟很适合Map类集合的遍历,因为他可以省略Iterator转换成Object的这一步。且第一种

这个是最简单的,代码复杂量也是最少的。

来看一道题:

方法一:

方法二:

方法三:

最简便的方法:

//HashMap默认的加载因子是0.75,初始最大容量是16,但他放不到16,因为比如我现在里面是空的,我的初始容量=0.75*16 = 12,也就是说我最多就存到12的时候他就会开始扩容,每次扩容为当前最大容量的两倍,也就是所说比如第一次到达临界值12的时候它的容量扩大为32,临界值就是32*0.75 = 24。

在jdk8以后,Map树化的机制

树化的条件有两个:1.链表层结点个数大于8(不等于)

                                  2.数组层长度大于等于64

上面这是一张HashMap的初始化图,初始容量为16,里面现在的16个node都是null,接着我再第三个结点的位置不停挂载8结点(代码层面就是把这8个哈希值都返回同一个值但是不要重写equals否则就会覆盖),在第三个结点的位置上形成链表,如下图

 现在数组索引为2地方有八个节点,此时的数组的最大容量=16,临界值为16*0.75 = 12.这两个都和最初默认的一样的,接着我在往所以为2的位置挂载第九个节点,此时链表超过八个了,在链表层已经满足树化的条件了,但是他在数组层的数组长度没有满足大于等于64,所以在挂载第九个几点的时候他的开始扩容,数组长度扩容为:最大长度 = 16*2=32; 临界值 = 32*0.75 = 24;此时还不满足树化条件,接着我再在索引为2的地方挂载第十个结点,数组再次扩容:

最大长度 = 32*2=64; 临界值 = 64*0.75 = 48;此时已经满足了树化的条件了。但是他还不会马上树化,他会在你下一次添加数据的时候树化,比如说我现在挂载第11个结点,此时不会再扩容,他现在会开始树化,原来在索引为2的那个地方的所有节点本来是以HashMap$Node的形式存在的,但是树化后的结点会以 HashMap$TreeNode的形式存在。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

new麻油叶先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值