HashMap是无序的

有一年多没有写博客了,懒久了就变得很烂,以前老大叫我写我不懂感恩,现在回来啪啪啪自己打脸~


一阵做了一个调查问卷的项目,viewpager+fragment来一道一道显示题目,每个fragment里显示一道题,包含题目和选项。我用了HashMap来存储题目id和对应的选项列表,结构是:

HashMap<String, List<Option>> optionMap = new HashMap<>();

到此没有问题。之后因为要用到最后一题的id,为了图方便,我将map转化为数组取数组最后一位:

        String [] ids  = mOptionMap.keySet().toArray(new String[0]);
        mLastQuestionId = ids[ids.length - 1];


但是得到的结果并不是最后一个问题的id,但是mOptionMap的size确实是问题总数,然后立马产生了一个疑问,难道HashMap是无序的?这应该是java基础,如果有人看到我的博客看到这是不是很震惊我竟然连这个都不知道。


然后看了下HashMap的实现原理,心理踏实多了。嗯, HashMap是无序的,如果有序的存储那就用LinkedHashMap:

  public LinkedHashMap<String, List<Option>> mOptionMap = new LinkedHashMap<>();

这样他存储的最后一个key就是最后一道题的id


要知道HashMap为什么是无序的,还是要来了解下他的实现原理:

HashMap是一个线性的数组,每个数组元素是一个链表,看下面的图就好理解,盗图来自HashMap实现原理分析:

无序


在源码里用Node<K,V>[] table来表示线性数组。每个元素是一个Node对象,Node里包含了key,value,和指向下一个元素的指针即Node<K, V> next。


当插入一个元素的时候,会根据key得到一个hash值,再通过该hash值与table的大小取模得到该元素应在数组中的位置索引,例如插入的k-V是(17, 30)那么计算17%16 = 1x16+1(HashMap中table数组默认的大小是16,扩容的话必须是2的指数),得到的索引index = 1。那么该元素就会被放到table[1]的位置上。如果此时再插入一个元素(33,30)经过计算得到的索引也是1,也要放到tabe[1]的位置上,此时的处理方式为将最新插入的元素放到头结点上,旧的元素挂在新插入元素的后面。所以数组里每个元素都是头结点,头结点都是最新插入的元素。如果此时又插入一个(33,9)呢,table[1]里已经存在了key值为33的元素了,那么该key为33的元素的value 30会被替换为最新的值即9,这也是为啥HashMap不允许重复key,其实就是值被替换了。


插入一个元素理解后,获取元素也就明了了,既然插入是通过计算得到一个index,那么取的时候自然也是要先计算得到这个index,然后遍历该位置的链表,找出key同的然后return value。


现在就能理解hashmap的无序了,即使是不同的key,但是如果有相同的hashcode(key的hash值%table.size),插入的元素就会落在table[index]链表上。





无序 hashmap
您的回应...

相关话题

查看全部

也许你感兴趣

换一批

热门标签

更多