java map遍历顺序_深入理解HashMap遍历元素的顺序
HashMap遍历元素的顺序。
一,HashMap元素的底层存储顺序
我们都知道HashMap是“无序”的,也就是说不能保证插入顺序。但是,HashMap其实也是有序的,一组相同的key-value对,无论他们插入的顺序是什么样的,遍历时,顺序都是一致的。
图片发自简书App
上面的代码,分别使用两种方式插入,也就是说插入顺序是不同的,但是遍历的结果是一样的。可以这样理解,只要你插入的是这19个元素,HashMap存储的时候,都是按照同一个顺序来存储的。
这一点其实也很容易理解,因为HashMap是使用hash算法来定位key的逻辑存储位置,只要你的key是一样的,逻辑存储位置也是一样的。
遍历结果如下:
11=11
12=12
13=13
14=14
15=15
16=16
17=17
18=18
19=19
0=0
1=1
2=2
3=3
4=4
5=5
6=6
7=7
8=8
9=9
10=10
为什么是这个顺序呢?本人很不理解。
如果说是根据key的hashcode来定位逻辑存储位置的话,关键key的hashcode也不支持这种说法啊。key的hashcode打印如下:
1568
1569
1570
1571
1572
1573
1574
1575
1576
49
50
51
52
53
54
55
56
57
1567
HashMap是通过hash算法把key映射到table数组的某个位置。以这个例子为例来说明,HashMap初始化容量指定为20,最终HashMap会把容量转化为32,那么这个HashMap的数组是一个长度为32的数组。
(为什么?稍后会说明)
OK,我们有一个长度为32的数组,接下来我们插入第一个元素,也就是key为0的一个字符串,这个key的hashcode值为48。那么这个key会被映射到数组的哪个位置呢?这个key对应数组的下标是多少呢?
这里有一个问题需要注意,长度为32的数组的下标必然是从0到31。然后这个数组的遍历顺序也是从0到31的顺序开始遍历。
查看源码我才发现,原来,数组的下标并不是key的hashcode值,而是key的hashcode值再经过按位与逻辑运算得到的。
先看一下源码,其他的代码我这里就不贴了,我只看最下面这行最关键的代码,如下图。
图片发自简书App
newTab[e.hash & (newCap - 1)] = e;
就是这行代码,这行代码就是把新增的节点Node放到数组中,放到数组中的哪个位置呢?
放到下标=e.hash & (newCap - 1)的位置!
好,那我就把e.hash & (newCap - 1)打印出来,看看到底是什么?
因为我们有20个元素,HashMap最终扩容以后的大小是32,也就是说:
newCap = 32
e. hash刚才说了,就是key的hashcode值,好,打印看看到底是什么鬼!
0-1-2-3-4-5-6-7-8-16-17-18-19-20-21-22-23-24-25-31
这就是结果!
这就是HashMap元素的存储顺序!
这就是HashMap元素的底层逻辑地址!
这!我的疑惑总算解开了!
下面再说一下2个关键问题:
1,指定的size大小是20,容量大小为什么变成了32。
2,HashMap为什么不直接用key的hashcode值来定位数组下标。
二,HashMap扩容的容量大小问题
HashMap初始化时,如果不指定,那么默认的容量大小为16。源代码中是这样的:
DEFAULT_INITIAL_CAPACITY = 1 << 4
但是我指定了容量为20,为什么就变成了32呢?
想搞清楚这个问题,必须清楚HashMap容量大小的计算逻辑。
源码如下:
图片发自简书App
这个方法是一系列的逻辑位运算。反正我现在是看不懂了,不过没关系,我把代码拿过来跑一下看看结果。
当入参是16的时候,返回16。
当入参是20的时候,返回是32。
原来如此啊,HashMap的容量大小必须是2的N次方。
结论:HashMap的容量必须是2的N次方,如果你指定了一个非2的N次方的整数S,那么HashMap在内部会把它转化为大于S的2的N次方的整数。
当然,这个整数是大于S的2的N次方的整数中最小的那一个。
三,HashMap为什么不直接用key的hashcode值来定位数组下标。
原因其实很简单,因为本例中HashMap的数组是一个长度为32的数组,下标从0到31。
key的hashcode值超过了31,就不行了。
所以,java的开发者做了一个映射,把key的hashcode值映射到0到31的区间范围。如何映射的呢?就是上面提到的:
e.hash & (newCap - 1)
把key的hashcode值与31做位与操作。
java的位与操作,忘记的可以自行脑补,我这里不在赘述,网上有很多讲解。我这里说一下java设计者的实现思路,为什么要这样实现。
为什么呢?因为HashMap是可以扩容的,newCap这个变量是动态的,本例中是32,但是如果是64呢,如果是256呢?
这时我就把这个newCap当做一个变量,接受用户输入。这样就成功把key的hashcode值映射到了指定范围的区间内:
【0到newCap减1】
这里的位与操作是关键,我们想把一些随机的整数映射到指定范围的区间时,可以考虑使用位与操作。这是计算机逻辑运算的特性,java的开发者们很好的利用了这一特性。
好了,今天的分享到此结束。
java map遍历顺序_深入理解HashMap遍历元素的顺序相关推荐
- hashmap中的key是有序的么_深入理解HashMap遍历元素的顺序
HashMap遍历元素的顺序. 一,HashMap元素的底层存储顺序 我们都知道HashMap是"无序"的,也就是说不能保证插入顺序.但是,HashMap其实也是有序的,一组相同的 ...
- 彻底理解HashMap的元素插入原理
转载自 彻底理解HashMap的元素插入原理 HashMap,是Java语言中比较基础也比较重要的一种数据结构,由于其用途广泛,所以,Java的工程师在设计HashMap的时候考虑了很多因素. 通 ...
- java注解的执行顺序_深入理解Spring的@Order注解和Ordered接口
前言 Spring的@Order注解或者Ordered接口大家都知道是控制顺序的,那么它们到底是控制什么顺序的?是控制Bean的注入顺序,还是Bean的实例化顺序,还是Bean的执行顺序呢?那么我们先 ...
- java map 值排序_使用Java8 Stream API对Map类型按照键或值进行排序
在这篇文章中,您将学习如何使用Java对Map按照键或值进行排序.前几日有位朋友面试遇到了这个问题,看似很简单的问题,但是如果不仔细研究一下也是很容易让人懵圈的面试题.所以我决定写这样一篇文章.在Ja ...
- java map增加值_Java程序以创建HashMap并添加键值对
要创建HashMap,请使用HashMap类-HashMap hm = new HashMap(); 以键值对形式将元素添加到HashMap-hm.put("Bag", new I ...
- Java Map集合常用API及3种遍历方式
1.map的常用API map是双列集合的顶层接口,是所有的双列集合都可以继承使用 2.使用Map集合 //1.创建Map集合的对象Map<String, String> m = new ...
- java阻塞队列作用_简单理解阻塞队列(BlockingQueue)中的take/put方法以及Condition存在的作用...
简单理解阻塞队列(BlockingQueue)中的take/put方法以及Condition存在的作用 Condition:可以理解成一把锁的一个钥匙,它既可以解锁(通知放行),又可以加锁(阻塞) n ...
- java map 变量_Java源码解析HashMap成员变量
本文基于jdk1.8进行分析 首先看一下HashMap的一些静态常量.第一个是DEFAULT_INITIAL_CAPACITY,默认初始大小,16.从注释中可以了解到,大小必须为2的指数.这里的16, ...
- java map用二叉树_【课堂笔记分享】linkedlist、二叉树、hashmap
LinkedList序列分先进先出FIFO,先进后出FILO FIFO在Java中又叫Queue 队列 FILO在Java中又叫Stack 栈 LinkedList 与 List接口与ArrayLis ...
最新文章
- linux时间轮算法,关于时间轮的设计 linux hashed Hierarchical timing wheel
- 深度学习时间序列预测:LSTM算法构建时间序列单变量模型预测空气质量(PM2.5)+代码实战
- 关于Android学习
- angularjs---服务(service / factory / provider)
- MySQL优化之my.conf配置详解
- PDF下载!提高代码质量的一本书
- why settype transport is not available in AG9 but works in AG3
- One order里user status和system status的mapping逻辑
- 【C++基础】C++11的noexcept声明符 与 异常传播
- 动态修改实体类转json的属性名
- 智慧数字门店管理系统、PAD、门店系统、收银开单、预约服务、会员管理、账单管理、数据统计、商品、库存、美容美体、美甲美睫、医疗美容、美发造型、医疗诊所、中医理疗、宠物服务、美业、经营业务、售卡、交班
- Python+OpenCV:理解支持向量机(SVM)
- (hdu step 6.3.3)Air Raid(最小路径覆盖:求用最少边把全部的顶点都覆盖)
- DNS分别在什么情况下使用UDP和TCP?
- Linux 制作安装程序(rpm,deb)的几个心得
- 如何通过SCJP考试(含真题分析和考点)
- 机器人对话系统的单轮对话和多轮对话
- 用C++开发的双人对战五子棋
- 树莓派4开发板无屏幕WIFI连接配置
- 京东Deco 智能代码体验版正式上线啦,快来体验设计稿一键生成代码~
热门文章
- MySql学习笔记(一):创建数据库,创建表,加载数据,数据检索
- linux cp -rf命令,Linux cp 命令详解
- 京东的“618”高并发秒杀终极版教程(Java 语言设计)
- jQuery框架的引入
- python学习笔记29(利用pycharm在windows下出现闪退以及turtle 入门)
- 微信WeStore将在2017微信公开课PRO版首次公开亮相
- ValueAnimator 中文翻译
- ecovrcs扫地机器人怎么升级_【七月更新】科沃斯扫地机器人&石头扫地机器人,如何选择?...
- Java算法题:利用字母可以组成一些美丽的图形,下面给出了一个例子:
- 为arcgis TXT转栅格的准备