ArrayMap 和HashMap的区别
在以往android开发中,我们常常用key-value存储数据时,随手就会打出HashMap的代码,当数据量较小时,这种方法还不错还可以,当数据量比较多的时候,如果是PC机上,也还阔以。但是如果使用设备是手机等移动设备,这是就要慎重了。手机内存不像PC内存那样,手机内存很宝贵,稍有不慎,可能就会引发OOM问题。那当数据量比较多,又需要在手机端开发,怎么解决内存问题呢?
这个时候,我们就可以用ArrayMap替代HashMap。ArrayMap相比传统的HashMap速度要慢,因为查找方法是二分法,并且当你删除或者添加数据时,会对空间重新调整,在使用大量数据时,效率低于50%。可以说ArrayMap是牺牲了时间换区空间。但在写手机app时,适时的使用ArrayMap,会给内存使用带来可观的提升。
那HashMap和ArrayMap到底不同在哪呢,主要有以下几个方面:
1、存储方式不同
HashMap内部有一个HashMapEntry<K, V>[]对象,每一个键值对都存储在这个对象里,当使用put方法添加键值对时,就会new一个HashMapEntry对象,具体实现如下:
[java] view plaincopy
@Override public V put(K key, V value) {
if (key == null) {
return putValueForNullKey(value);
}
int hash = secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
int index = hash & (tab.length - 1);
//先查找有没有对应的key值,如果有,就改写value,并返回改写前的value值:oldValue
for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
preModify(e);
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
// No entry for (non-null) key is present; create one
modCount++;
if (size++ > threshold) {
//扩容,双倍
tab = doubleCapacity();
index = hash & (tab.length - 1);
}
addNewEntry(key, value, hash, index);
return null;
}
//创建对象存储键值对
void addNewEntry(K key, V value, int hash, int index) {
table[index] = new HashMapEntry<K, V>(key, value, hash, table[index]);
}
ArrayMap的存储中没有Entry这个东西,他是由两个数组来维护的
[java] view plaincopy
int[] mHashes;
Object[] mArray;
mHashes数组中保存的是每一项的HashCode值,mArray中就是键值对,每两个元素代表一个键值对,前面保存key,后面的保存value,我们看看下面代码的结果:
[java] view plaincopy
arraymap = new HashMap<String, String>();
a.put("a", "a_value");
a.put("b", "b_value");
执行上面代码后,arraymap中的存储是这样的
![]() |
是不是能清楚地看到ArrayMap的存储了,这种存储在put代码中如下:
[java] view plaincopy
mHashes[index] = hash;
mArray[index<<1] = key;
mArray[(index<<1)+1] = value;
2、添加数据时扩容时的处理不一样
先来看看HashMap
[java] view plaincopy
if (size++ > threshold) {
tab = doubleCapacity();
index = hash & (tab.length - 1);
}
doubleCapacity进行双倍扩容,它的代码中有这么一句话
[java] view plaincopy
HashMapEntry<K, V>[] newTable = makeTable(newCapacity);
最终,这个newTable将作为扩容后的新对象返回,那么makeTable做了什么呢,如下:
[java] view plaincopy
private HashMapEntry<K, V>[] makeTable(int newCapacity) {
@SuppressWarnings("unchecked") HashMapEntry<K, V>[] newTable
= (HashMapEntry<K, V>[]) new HashMapEntry[newCapacity];
table = newTable;
threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity
return newTable;
}
我们清楚地看到,这里进行了new操作,重新创建对象,开销很大。
那么ArrayMap呢,看看:
[java] view plaincopy
//如果容量不够
ize >= mHashes.length) {
final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1))
: (mSize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);
if (DEBUG) Log.d(TAG, "put: grow from " + mHashes.length + " to " + n);
final int[] ohashes = mHashes;
final Object[] oarray = mArray;
//分配数组
allocArrays(n);
if (mHashes.length > 0) {
if (DEBUG) Log.d(TAG, "put: copy 0-" + mSize + " to 0");
//特别注意这,是copy,而不是new,效率提升
System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
System.arraycopy(oarray, 0, mArray, 0, oarray.length);
}
//释放无用空间,收缩数组
freeArrays(ohashes, oarray, mSize);
}
ArrayMap用的是copy数据,所以效率相对要高。
3、ArrayMap提供了数组收缩的功能,在clear或remove后,会重新收缩数组,是否空间
4、ArrayMap采用二分法查找;
以上就是android开发中,HashMap与ArrayMap的区别,大家在涉及到内存方面的实现,可根据实际情况选择这两种不同的方式。
ArrayMap 和HashMap的区别的更多相关文章
- HashSet和HashMap的区别
HashSet和HashMap的区别.Java的HashSet类是由哈希表支持.它不保证 set 的迭代顺序:特别是它不保证该顺序恒久不变.此类允许使用 null 元素.HashSet类为基本操作提供 ...
- HashSet与HashMap的区别
本文由 ImportNew - 唐小娟 翻译自 Javarevisited.欢迎加入翻译小组.转载请见文末要求. HashMap和HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到C ...
- HashSet HashTable HashMap的区别 及其Java集合介绍
(1)HashSet是set的一个实现类,hashMap是Map的一个实现类,同时hashMap是hashTable的替代品(为什么后面会讲到). (2)HashSet以对象作为元素,而HashMap ...
- WeakHashMap和HashMap的区别
看Java源码的时候,看到了 WeakHashMap ,我一直以来使用的 都是 HashMap,于是查了一下两者的区别 (一) 查看API文档,WeakHashmap要点如下: 1. 以弱键 实现的基 ...
- HashSet HashTable HashMap的区别
(1)HashSet是set的一个实现类,hashMap是Map的一个实现类,同时hashMap是hashTable的替代品(为什么后面会讲到). (2)HashSet以对象作为元素,而HashMap ...
- C# Hashtable 使用说明 以及 Hashtable和HashMap的区别
一,哈希表(Hashtable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似key/value的键值对,其 ...
- Java容器类List、ArrayList、Vector及map、HashTable、HashMap的区别与用法
Java容器类List.ArrayList.Vector及map.HashTable.HashMap的区别与用法 ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数 ...
- [转]合理使用ArrayMap代替HashMap
合理使用ArrayMap代替HashMap 2016年07月08日 15:34:44 阅读数:5938 转载请标注: 披萨大叔的博客 http://blog.csdn.net/qq_27258799/ ...
- HashTable, HashSet, HashMap的区别
HashTable, HashSet, HashMap的区别 hash是一种很常见也很重要的数据结构,是用hash函数根据键值(key)计算出存储地址,以便直接访问.由完美hash函数(即键值 ...
随机推荐
- iview导航菜单updateOpened和updateActiveName的使用
先看官方文档: iview导航菜单 这里主要遇到的问题有两个: 1. 点击回到首页(B按钮)时需要取消选中当前选中的菜单项(全部不选中),这里用到的是 updateActiveName方法 2. 点击 ...
- wsgiref源码解析
wsgiref是PEP 333定义的wsgi规范的范例实现,里面的功能包括了: wsgi的环境变量 应答头部的处理 实现简单的HTTP服务器 简单的对程序端和服务器端校验函数 我们先看一个简单的代码实 ...
- 【ABP框架系列学习】模块系统(4)之插件示例开发
0.引言 上一篇博文主要介绍了ABP模块及插件的相关知识,本章节主要开发一个插件示例来学习如何创建一个插件,并在应用程序中使用.这个命名为FirstABPPlugin的插件主要在指定的时间段内删除审计 ...
- sql server 备份与恢复系列二 事务日志概述
1.1 日志文件与数据文件一致性 在上一章备份与恢复里了解到事务日志的重要性,这篇重点来了解事务日志. 事务日志记录了数据库所有的改变,能恢复该数据库到改变之前的任意状态.在sql server实例 ...
- Java集合框架总结—超详细-适合面试
Java集合框架总结—超详细-适合面试 一.精简: A.概念汇总 1.Java的集合类主要由两个接口派生而出:Collection和Map,Collection和Map是Java集合框架的根接口, ...
- 07 训练Tensorflow识别手写数字
打开Python Shell,输入以下代码: import tensorflow as tf from tensorflow.examples.tutorials.mnist import input ...
- Linux两台主机之间建立信任(ssh免密码)
背景: 有时候我们在两个主机之间复制文件的时候,提示输入密码,很不方便,那如何免密码复制呢?,就是使用通过linux公钥和秘钥,建立双机信任关系. 在整理之前,我先说下ssh免密码的要点 : 你想免密 ...
- 伪指令 ADR 与 LDR 的区别
指令简介: adr r0, _start 得到的是 _start 的当前执行位置,由 pc+offset 决定 ldr r0, =_start 得到的是绝对的地址,链接时决定 程序示例: ldr r0 ...
- Video for Linux Two API Specification
V4L2 的使用规范,网址为:https://www.linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/spec-single/v4l2.ht ...
- 第一册:lesson twenty seven。
原文 :Mrs.smith's living room. Mrs.smith's living room is large. There is a television in the room. Th ...
