Android小知识-如何正确的选择HashMap、LinkedHashMap和ArrayMap

本平台的文章更新会有延迟,大家可以关注微信公众号-顾林海,包括年底前会更新kotlin由浅入深系列教程,目前计划在微信公众号进行首发,如果大家想获取最新教程,请关注微信公众号,谢谢

在Android应用开发中,HashMap使用最频繁的容器之一,但它并不是最节约的容器,会占用大量内存。

HashMap是一个散列链表,向HashMap中put元素时,先根据key的HashCode重新计算hash值,根据hash值得到这个元素在数组中的位置,如果该位置已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放链头,最先加入的放链尾。如果该位置上没有元素,就直接将该元素放到此数组中指定的位置。

也就是说,向HashMap插入一个对象前,会给一个通向Hash阵列的索引,在索引的位置中,保存了这个Key对象的值。

这意味着需要考虑的一个最大问题是冲突,也就是Hash冲突,当多个对象散列于阵列相同位置时,就会有散列冲突的问题。因此,HashMap会配置一个大的数组来减少潜在的冲突,并且会有其他的逻辑防止链接算法和一些冲突的发生。

从节省内存的角度来看,使用HashMap不是一个正确的选择,为此Android提供了一个替代容器,也就是ArrayMap。

ArrayMap提供了和HashMap一样的功能,但能避免过多的内存开销,方法是使用两个小数组,而不是一个大数组。其中一个数组记录对象Key Hash过后的顺序列表,另一个数组按Key的顺序记录Key-Value值,根据Key数组的顺序,交织在一起。

在需要获取某个Value时,ArrayMap会计算输入Key转换过后的hash值,然后使用二分查找法对Hash数组寻找到对应的index,然后可以通过这个index在另外一个数组中直接访问需要的键值对。如果在第二个数组键值对中的key和前面输入的查询key不一致,就认为发生了碰撞冲突。为了解决这个问题,ArrayMap会以该key为中心点,分别上下展开,逐个对比查找,直到找到匹配的值。

因此会带来一个问题,就是随着ArrayMap中对象数量的增加,需要访问单独对象的时间也会变长。

在ArrayMap中执行插入或者删除操作时,从性能角度上看,比HashMap还要更差一些,但如果只涉及很小的对象数,比如1000以下,就不需要担心这个问题。当值特别小时,相比HashMap,ArrayMap能节省更多的内存。

使用ArrayMap总结如下:

  • 当对象的数目非常小(1000以内),但是访问特别多,或者删除和插入频率不高时使用ArrayMap。

  • 当有映射容器,有映射时,并且所有映射的容器也是ArrayMap时使用ArrayMap。

LinkedHashMap 直接继承自HashMap ,这也就说明了 HashMap 一切重要的概念 LinkedHashMap 都是拥有的,这就包括了,hash 算法定位 hash 桶位置,哈希表由数组和单链表构成,并且当单链表长度超过 8 的时候转化为红黑树,扩容体系,这一切都跟 HashMap 一样。那么除了这么多关键的相同点以外,LinkedHashMap 比 HashMap 更加强大,这体现在:

LinkedHashMap 内部维护了一个双向链表,解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题

LinkedHashMap 元素的访问顺序也提供了相关支持,也就是我们常说的 LRU(最近最少使用)原则。

LinkedHashMap 拥有与 HashMap 相同的底层哈希表结构,即数组 + 单链表 + 红黑树,也拥有相同的扩容机制。相比 HashMap 的拉链式存储结构,内部额外通过 Entry 维护了一个双向链表。HashMap 元素的遍历顺序不一定与元素的插入顺序相同,而 LinkedHashMap 则通过遍历双向链表来获取元素,所以遍历顺序在一定条件下等于插入顺序。LinkedHashMap 可以通过构造参数accessOrder 来指定双向链表是否在元素被访问后改变其在双向链表中的位置。



扫码_搜索联合传播样式-标准色版.png

Android、Java、Python、Go、PHP、IOS、C++、HTML等等技术文章,更有各种书籍推荐和程序员资讯,快来加入我们吧!关注技术共享笔记。

838794-506ddad529df4cd4.webp.jpg

搜索微信“顾林海”公众号,定期推送优质文章。

你可能感兴趣的:(Android小知识-如何正确的选择HashMap、LinkedHashMap和ArrayMap)