SparseArray代替HashMap

相信大家都明白,手机软件的开发不同于PC软件的开发,因为手机性能相对有限,内存也有限,所谓“寸土寸金”,可能稍有不慎,就会导致性能的明显降低。Android为了方便开发者,特意在android.util这个包中提供了几个提高效率的工具类,比如之前用过的LruCache类,这次我们来谈谈其他工具类,SparseArray,SparseBooleanArray和 SparseIntArray。

 

总体说,它们都是类似map这样key-value的存储方式,但是由于查找的算法不一样。因此效率也各不同。但要明白,没有说哪个一定是最好的。只有根据不同需求在不同场景去应用,才能获取较优的结果。下面我们来看看它们的“庐山真面目”吧。

 

SparseArray

本来想在这里好好介绍何为SparseArray。但看完源码和官方的文档,发现里面已经介绍的很仔细了。于是决定将源码中开始关于介绍SparseArray的那一段翻译在这里,最后总计几个要点。英文水平有限,翻译不恰当的地方请先见谅。

package android.util;  import com.android.internal.util.ArrayUtils;  /** * SparseArrays 利用integer去管理object对象。不像一个正常的object对象数组,它能在索引数中快速的查找到所需的结果。(这 * 句话是音译,原意是能在众多索引数中“撕开一个缺口”,为什么原文这么表达?下面会慢慢说清楚。)它比HashMap去通过Integer索引 * 查找object对象时在内存上更具效率,不仅因为它避免了用来查找的自动“装箱”的keys,并且它的数据结构不依赖额外的对象去 * 各个映射中查找匹配。 *  * SparseArrays map integers to Objects.  Unlike a normal array of Objects, * there can be gaps in the indices.  It is intended to be more memory efficient * than using a HashMap to map Integers to Objects, both because it avoids * auto-boxing keys and its data structure doesn't rely on an extra entry object * for each mapping. * * 请注意,这个容器会保持它的映射关系在一个数组的数据结构中,通过二分检索法驱查找key。(这里我们终于知道,为何这个工具类中, * 提供的添加映射关系的操作中,key的类型必须是integer。因为二分检索法,将从中间“切开”,integer的数据类型是实现这种检索过程的保证。) *  * 如果保存大量的数据,这种数据结构是不适合的,换言之,SparseArray这个工具类并不应该用于存储大量的数据。这种情况下,它的效率 * 通常比传统的HashMap更低,因为它的查找方法并且增加和移除操作(任意一个操作)都需要在数组中插入和删除(两个步骤才能实现)。 *  * 如果存储的数据在几百个以内,它们的性能差异并不明显,低于50%。 *  * (OK,那么光看Android官方的介绍我们就有初步结论了,大量的数据我们相对SparseArray会优先选择HashMap,如果数据在几百个这个数目, *  那么选择它们任意一个去实现区别不大,如果数量较少,就选择SparseArray去实现。 其实如果我们理解了二分法,就很容易了SparseArray的 *  实现原理,以及SparseArray和HashMap它们之间的区别了。) *  * <p>Note that this container keeps its mappings in an array data structure, * using a binary search to find keys.  The implementation is not intended to be appropriate for * data structures * that may contain large numbers of items.  It is generally slower than a traditional * HashMap, since lookups require a binary search and adds and removes require inserting * and deleting entries in the array.  For containers holding up to hundreds of items, * the performance difference is not significant, less than 50%.</p> * *   * 为了提高性能,这个容器包含了一个实现最优的方法:当移除keys后为了立刻使它的数组紧密,它会“遗留”已经被移除(标记了要删除)的条目(entry) 。 * 所被标记的条目(entry)(还未被当作垃圾回收掉前)可以被相同的key复用,也会在垃圾回收机制当作所有要回收的条目的一员被回收,从而使存储的数组更紧密。 *  * (我们下面看源码就会发现remove()方法其实是调用delete()方法的。印证了上面这句话所说的这种优化方法。 * 因为这样,能在每次移除元素后一直保持数组的数据结构是紧密不松散的。) *  * 垃圾回收的机制会在这些情况执行:数组需要扩充,或者映射表的大小被恢复,或者条目值被重新检索后恢复的时候。 *   * <p>To help with performance, the container includes an optimization when removing * keys: instead of compacting its array immediately, it leaves the removed entry marked * as deleted.  The entry can then be re-used for the same key, or compacted later in * a single garbage collection step of all removed entries.  This garbage collection will * need to be performed at any time the array needs to be grown or the the map size or * entry values are retrieved.</p> * * 当调用keyAt(int)去获取某个位置的key的键的值,或者调用valueAt(int)去获取某个位置的值时,可能是通过迭代容器中的元素 * 去实现的。 * * <p>It is possible to iterate over the items in this container using * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending * order in the case of <code>valueAt(int)<code>.</p> */  
public class SparseArray<E> implements Cloneable {  //...  
}  

 

至于完整的源码就不贴出来了,因为不多,大家可以自行看看。

 

这里总结下几个重要的点:

1,SparseArray的原理是二分检索法,也因此key的类型都是整型。

2,(HashMap和SparseArray比较)当存储大量数据(起码上千个)的时候,优先选择HashMap。如果只有几百个,用哪个区别不大。如果数量不多,优先选择SparseArray。

3,SparseArray有自己的垃圾回收机制。(当数量不是很多的时候,这个不必关心。)

接着将里面的主要方法列出来:

private int index = 1;  private String value = "value";  public void testSparseArray()  {  //创建一个SparseArray对象  SparseArray<String> sparseArray = new SparseArray<String>();  //向sparseArray存入元素value,key为index  sparseArray.put(index, value);  //这个方法本质也是利用put(key, value)去存入数据  sparseArray.append(index, value);  sparseArray.indexOfKey(index);  //查找value所在的位置,如果不存在,则返回-1  sparseArray.indexOfValue(value);  //更新某个key的值  sparseArray.setValueAt(index, value);  //获取index所对应的值,没有则返回null  sparseArray.get(index);  //获取index所对应的值,没有则返回自定义的默认值"default-value"  sparseArray.get(index,"default-value");  //删除index对应的元素  sparseArray.delete(index);  //移除,本质也是调用delete(int)方法  sparseArray.remove(index);  //清空所有数据  sparseArray.clear();  }  

SparseBooleanArray和SparseIntArray

SparseBooleanArray和SparseIntArray,其实看名字也知道,它们跟SparseArray极其类似,只是存储类型加以限制了。SparseBooleanArray只能存储boolean值,而SparseIntArray只能存储integer类型的值。它们也同样实现了Cloneable接口,可以直接调用clone方法,也同样是以二分法为依据。而其他的主要方法也是一样的。下面以SparseBooleanArray为简单例子写出主要的方法,从方法看出,两者和SparseArray的确是灰常类似的。SparseIntArray的代码就不再贴出来了,因为都一样的。我们在使用的过程中举一反三,会用一个,其他2个也就会用了呢。

public void testSparseBooleanArray()  {  //      SparseBooleanArray sparseBooleanArray = new SparseBooleanArray();  //这种创建方式可以设置容器的大小  SparseBooleanArray sparseBooleanArray = new SparseBooleanArray(5);  //存入数据,同样有两种方法  sparseBooleanArray.put(int, boolean);  sparseBooleanArray.append(int, boolean);  //根据key获取对应的boolean值,没有则返回false  sparseBooleanArray.get(key);  //跟上面类似,valueIfKeyNotFound是自定义的假设不存在则返回的默认值  sparseBooleanArray.get(key, valueIfKeyNotFound);  //获取第5个位置的键值  sparseBooleanArray.keyAt(5);  //获取第5个元素的值  sparseBooleanArray.valueAt(5);  //删除某个key的元素  sparseBooleanArray.delete(key);  //清除所有  sparseBooleanArray.clear();  }  

那么SparseBooleanArray和SparseIntArray也和SparseArray一样,存储不是太多的数据,它们都是作为比HashMap更好的选择。但数据是死的,功能也是死的,实现方式是灵活的。条条大路通罗马。我们不能一概而论说谁好谁差,放在具体的场景,才能选择更高效也更合乎成本的实现方式。

转载于:https://www.cnblogs.com/ganchuanpu/p/7696251.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/280085.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

也许你曾经读过他的书

我们愿用“能理能文、才华多元”来形容他。因为热爱编程和游戏&#xff0c;所以他将爱好变成了职业&#xff0c;并在这条路上持续奔跑&#xff1b;因为热爱分享&#xff0c;所以他坚持在博客上分享技术观点并出版了关于 Azure、微软游戏栈的书籍&#xff1b;因为热爱挑战&#…

python测试框架数据生成工具最全资源汇总

xUnit frameworks 单元测试框架frameworks 框架unittest - python自带的单元测试库&#xff0c;开箱即用unittest2 - 加强版的单元测试框架&#xff0c;适用于Python 2.7以及后续版本pytest - 成熟且功能强大的单元测试框架plugincompat - pytest的执行及兼容性插件nosetests -…

t30智能插座怎么设置_如何设置ConnectSense智能插座

t30智能插座怎么设置If you like the idea of smart outlets, but wish you had one with more than just one receptacle on it, the ConnectSense Smart Outlet is worth looking into. Here’s how to set it up and instantly get double the fun. 如果您喜欢智能插座的想法…

用链表和数组实现HASH表,几种碰撞冲突解决方法

Hash算法中要解决一个碰撞冲突的办法&#xff0c;后文中描述了几种解决方法。下面代码中用的是链式地址法&#xff0c;就是用链表和数组实现HASH表。 he/*hash table max size*/ #define HASH_TABLE_MAX_SIZE 40/*hash table大小*/ int hash_table_size0;/*.BH----------------…

安卓操作sqlite3,增删改查

创建 layout <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:orientation"vertical"android:layout_width"match_parent"android:layo…

基于.NetCore开发博客项目 StarBlog - (23) 文章列表接口分页、过滤、搜索、排序

1前言上一篇留的坑&#xff0c;火速补上。在之前的第6篇中&#xff0c;已经有初步介绍&#xff0c;本文做一些补充&#xff0c;已经搞定这部分的同学可以快速跳过&#xff0c;基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表对标准的WebApi来说&#xff0c;分…

如何在Chrome中保存您当前的所有标签,以便以后阅读

Chrome allows you to open tabs from your last browsing session when you open the browser. However, what if you want to save your current set of tabs to re-open at any time? Chrome doesn’t provide a way to do that natively, but there is an easy workaround…

ubuntu 16.04(Windows 10双系统+grub引导)无法进入tt1~tt6(NVIDIA驱动安装相关-黑屏,login loop,分辨率)...

目录 前言回顾最终解决&#xff1a;0.关闭x服务1.禁用nouveau2.加入3.更新4.查找匹配驱动5.选择推荐版本6.等待安装后重启,nvidia-smi查看是否安装成功,或者lsmod | grep nvidia&#xff0c;成功结果如下7.重启x服务8.此时还不能进入图形界面&#xff0c;因为nomodeset还在&…

(备忘)打开office2010总是在配置进度

1、同时按上键盘上面的windows键和R键&#xff0c;出现“运行” 2、输入“regedit”&#xff0c;回车进入注册表 3、点击“HKEY_CURRENT_USER”展开&#xff0c;依次“Software”--“Microsoft”--“Office”--"14.0"--"Word"展开&#xff0c;点击"Op…

java、oracle对CLOB处理

oracle CLOB字段转换位VARCHAR 1.实际上处理CLOB字段的时候&#xff0c;直接TO_CHAR&#xff0c;当长度超过4000的时候&#xff0c;会报错&#xff0c;提示列被截取&#xff1b; CLOB转varchar2&#xff1a;select to_char(CLOB字段) from table 2.直接使用SUBSTR对CLOB字段进行…

android 更改软键盘_如何在Android的Google键盘上更改声音和振动

android 更改软键盘Tactile feedback from a touch screen keyboard is crucial, in my opinion, but I don’t like sounds when I tap keys. You may not be like me—maybe sounds are your thing, but vibration is annoying. Or maybe you dislike both (you rebel!). The…

『 再看.NET7』看看required属性有什么不同

还是先看看C#中属性的这定义&#xff0c;在初始化和访问上有哪些方式&#xff0c;就能看出required属性有什么不一样的地方了。属性&#xff0c;是封装字段的&#xff0c;通过get和set访问器可以很好地验证数据的有效性。public record Order_00 {public Guid Id { get; set; }…

知识点:Mysql 索引原理完全手册(1)

知识点&#xff1a;Mysql 索引原理完全手册(1) 知识点&#xff1a;Mysql 索引原理完全手册(2) 知识点&#xff1a;Mysql 索引优化实战(3) 知识点&#xff1a;Mysql 数据库索引优化实战(4) Mysql-索引原理完全手册 一、 介绍二、 索引的原理三、 索引的数据结构四、 聚集索引与辅…

如何将Apple Mail建议用于事件和联系人

Apple products come preinstalled with an email client that can, on occasion, be quite smart. Today we want to show you another great feature: suggestions for event and contacts. Apple产品预装了一个电子邮件客户端&#xff0c;该客户端有时可能非常聪明。 今天&a…

TPshop表结构

tp_account_log -- 账户表 字段名字段类型默认值描述log_idmediumint(8) unsigned 日志iduser_idmediumint(8) unsigned 用户iduser_moneydecimal(10,2)0.00用户金额frozen_moneydecimal(10,2)0.00冻结金额pay_pointsmediumint(9) 支付积分change_timeint(10) unsigned 变动时间…

Redis 通配符批量删除key

问题&#xff1a; 线上有部分的redis key需要清理。 一、 由于Keys模糊匹配&#xff0c;请大家在实际运用的时候忽略掉。因为Keys会引发Redis锁&#xff0c;并且增加Redis的CPU占用&#xff0c;情况是很恶劣的&#xff0c; 官网说明如下&#xff1a; Warning: consider KEYS as…

如何在 .Net 7 中将 Query 绑定到数组

在 .Net 7 中&#xff0c;我们可以通过绑定数组的方式来接收来自查询字符串的参数。这样就不需要再使用逗号分隔的字符串来获取参数了。代码演示 假设我们需要从 query 上接受多个 id 并返回查询的结果。例如&#xff1a;id1&id2在 .Net 7 中&#xff0c;我们可以这样实现&…

xbox one 越狱_如何在Xbox One上播放视频和音乐文件

xbox one 越狱The Xbox One has integrated TV features and support for streaming media apps like Netflix and Hulu, but that isn’t where it ends. You can play video and music files you’ve ripped or downloaded by plugging in a USB drive or streaming them ove…

C++实验七

11——3 #include<fstream>using namespace std;int main(){ ofstream file; file.open("test1.txt",ios_base::binary); file<<"已成功添加字符&#xff01;"; file.close(); return 0; } 11-4 #include<fstream>#include<iostrea…

Visual Studio 15.4发布,新增多平台支持

微软发布了Visual Studio 2017的第四个升级版本&#xff0c;并且延续了支持.NET Standard 2.0和通用Windows平台&#xff08;UWP&#xff09;的承诺。.NET Standard 2.0支持是微软推动跨平台应用程序开发和代码重用战略的重要一环。\\15.4版本的变化与微软发布的预览版非常接近…