内容简介:ArrayMap是通用的键值对映射数据结构,相比传统的HashMap有更高的内存利用率。使用数组的数据结构保存映射:一个整形数组存放每项的哈希值,一个Object数组存放键值对。通过使用数组,能避免为每个放入Map的entry创建额外的对象(对比HashMap的Node),并能更有力地控制数组扩展的大小(扩增数组只需要创建一个新的数组并拷贝元素,不是重建hash map)。此数据结构不适合用在存放大量items的场景。相比传统HashMap,ArrayMap速度要更慢。因为ArrayMap通过二分查找搜索
一、类签名
ArrayMap是通用的键值对映射数据结构,相比传统的HashMap有更高的内存利用率。使用数组的数据结构保存映射:一个整形数组存放每项的哈希值,一个Object数组存放键值对。通过使用数组,能避免为每个放入Map的entry创建额外的对象(对比HashMap的Node),并能更有力地控制数组扩展的大小(扩增数组只需要创建一个新的数组并拷贝元素,不是重建hash map)。
public final class ArrayMap<K, V> implements Map<K, V>
此数据结构不适合用在存放大量items的场景。相比传统HashMap,ArrayMap速度要更慢。因为ArrayMap通过二分查找搜索item,添加或移除元素也需要操作数组的entries。不过容器仅持有的数百个items时,两者的性能差别并不明显,差别不超过50%。
为了更平衡的内存利用率,ArrayMap不像其他的标准 Java 容器类,而是会在items移除的同时缩小数组。现在也不能主动控制数组的缩小,也就是说,设置了capacity,当任意item被移除,数组的大小都会减少到刚好容纳所有item的大小。
源码来自Android 26
二、常量
private static final boolean CONCURRENT_MODIFICATION_EXCEPTIONS = true; // 最低扩容容量 private static final int BASE_SIZE = 4; // cache size大小 private static final int CACHE_SIZE = 10; // 特殊的哈希数组值,用来表示container不可变 static final int[] EMPTY_IMMUTABLE_INTS = new int[0]; // 特殊的不可变空ArrayMap常量,主要用于表示空状态 public static final ArrayMap EMPTY = new ArrayMap<>(-1);
三、成员变量
// 缓存小数组对象避免垃圾回收 // mBaseCache[0]指向列表中的下一个数组 // mBaseCache[1]指向int[] static Object[] mBaseCache; static int mBaseCacheSize; // 缓存小数组对象避免垃圾回收 static Object[] mTwiceBaseCache; static int mTwiceBaseCacheSize; final boolean mIdentityHashCode; // 哈希数组 int[] mHashes; // 存放key-value的数组 Object[] mArray; // 已保存items数量 int mSize; MapCollections<K, V> mCollections;
四、构造方法
// 构造空ArrayMap,初始默认容量为0 public ArrayMap() { this(0, false); } // 根据给定的容量值构造实例 public ArrayMap(int capacity) { this(capacity, false); } public ArrayMap(int capacity, boolean identityHashCode) { mIdentityHashCode = identityHashCode; if (capacity < 0) { // 此实例内容是不可变的,使用常量标记 mHashes = EMPTY_IMMUTABLE_INTS; mArray = EmptyArray.OBJECT; } else if (capacity == 0) { // 此实例内容可变,但初始大小为0 mHashes = EmptyArray.INT; mArray = EmptyArray.OBJECT; } else { // 根据指定大小进行构造 allocArrays(capacity); } // 以保存元素数量为0 mSize = 0; } // 根据给定的map构造实例 public ArrayMap(ArrayMap<K, V> map) { this(); if (map != null) { putAll(map); } }
五、静态方法
// 二分查找 private static int binarySearchHashes(int[] hashes, int N, int hash) { try { return ContainerHelpers.binarySearch(hashes, N, hash); } catch (ArrayIndexOutOfBoundsException e) { if (CONCURRENT_MODIFICATION_EXCEPTIONS) { throw new ConcurrentModificationException(); } else { throw e; // the cache is poisoned at this point, there's not much we can do } } } // 释放hash数组与key-value数组 // 合适的数组不会释放而是缓存起来,下次数组大小合适时复用 private static void freeArrays(final int[] hashes, final Object[] array, final int size) { // hashes.length == 8 if (hashes.length == (BASE_SIZE*2)) { synchronized (ArrayMap.class) { // mTwiceBaseCacheSize最多保存10个 if (mTwiceBaseCacheSize < CACHE_SIZE) { // 通过链表的方法保存 array[0] = mTwiceBaseCache; array[1] = hashes; // 置空数组索引[2,(size<<1)-1]的entry for (int i=(size<<1)-1; i>=2; i--) { array[i] = null; } mTwiceBaseCache = array; mTwiceBaseCacheSize++; // 已保存数量递增 } } } else if (hashes.length == BASE_SIZE) { // hashes.length == 4 synchronized (ArrayMap.class) { // mBaseCacheSize最多保存10个 if (mBaseCacheSize < CACHE_SIZE) { array[0] = mBaseCache; // index = 0 array[1] = hashes; // index = 1 // 置空数组index [2,(size<<1)-1]的entry for (int i=(size<<1)-1; i>=2; i--) { array[i] = null; } mBaseCache = array; mBaseCacheSize++; // 已保存数量递增 } } } }
六、成员方法
// 通过key和hash找索引 int indexOf(Object key, int hash) { final int N = mSize; // ArrayMap为空,返回~0 if (N == 0) { return ~0; } // 通过二分查找确认索引值 int index = binarySearchHashes(mHashes, N, hash); // 如果找不到哈希码,表示此key没有对应的Entry if (index < 0) { return index; } // 该key和index所表示的'key'匹配,则表示index成功命中 if (key.equals(mArray[index<<1])) { return index; } // 从index开始,检查后方索引的key是否匹配 int end; for (end = index + 1; end < N && mHashes[end] == hash; end++) { if (key.equals(mArray[end << 1])) return end; // 返回匹配的索引值 } // 从index开始,检查前方索引的key是否匹配 for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) { if (key.equals(mArray[i << 1])) return i; // 返回匹配的索引值 } // Key not found -- return negative value indicating where a // new entry for this key should go. We use the end of the // hash chain to reduce the number of array entries that will // need to be copied when inserting. return ~end; } int indexOfNull() { final int N = mSize; // ArrayMap为空,返回~0 if (N == 0) { return ~0; } int index = binarySearchHashes(mHashes, N, 0); // If the hash code wasn't found, then we have no entry for this key. // 哈希值没有命中,表示此kay没有对应的entry. if (index < 0) { return index; } // If the key at the returned index matches, that's what we want. // 该key和index所表示的'key'匹配,则表示index成功命中 if (null == mArray[index<<1]) { return index; } // 从index开始,检查后方索引的key是否匹配 int end; for (end = index + 1; end < N && mHashes[end] == 0; end++) { if (null == mArray[end << 1]) return end; } // 从index开始,检查前方索引的key是否匹配 for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) { if (null == mArray[i << 1]) return i; } // Key not found -- return negative value indicating where a // new entry for this key should go. We use the end of the // hash chain to reduce the number of array entries that will // need to be copied when inserting. return ~end; } // 分配数组空间 private void allocArrays(final int size) { // 若mHashes为EMPTY_IMMUTABLE_INTS,表示此ArrayMap是不可变的,并抛出异常 if (mHashes == EMPTY_IMMUTABLE_INTS) { throw new UnsupportedOperationException("ArrayMap is immutable"); } // size == 8,从缓存中复用数组 if (size == (BASE_SIZE*2)) { synchronized (ArrayMap.class) { if (mTwiceBaseCache != null) { final Object[] array = mTwiceBaseCache; mArray = array; // mTwiceBaseCache = mTwiceBaseCache[0] mTwiceBaseCache = (Object[])array[0]; // 取出缓存的hashes赋值给mHashes复用 mHashes = (int[])array[1]; // 置空索引0和索引1的空间 array[0] = array[1] = null; // 已缓存数组数量递减 mTwiceBaseCacheSize--; return; } } } else if (size == BASE_SIZE) { // size == 4,从缓存中复用数组 synchronized (ArrayMap.class) { if (mBaseCache != null) { final Object[] array = mBaseCache; mArray = array; // mBaseCache = mBaseCache[0] mBaseCache = (Object[])array[0]; // 取出缓存的hashes赋值给mHashes复用 mHashes = (int[])array[1]; // 置空索引0和索引1的空间 array[0] = array[1] = null; // 已缓存数组数量递减 mBaseCacheSize--; return; } } } // size大小不是4或8,则就地创建新数组并赋值 mHashes = new int[size]; mArray = new Object[size<<1]; } // 清空所有键值对数据 @Override public void clear() { // 以保存元素数量不为空 if (mSize > 0) { // ohashes i.e oldHashes final int[] ohashes = mHashes; // oarray i.e oldArray final Object[] oarray = mArray; // osize i.e oldSize final int osize = mSize; // 设置EmptyArray.INT表明为空 mHashes = EmptyArray.INT; // 设置EmptyArray.OBJECT表明为空 mArray = EmptyArray.OBJECT; // 已保存item为0 mSize = 0; // 释放数组空间 freeArrays(ohashes, oarray, osize); } // 检查是否存在并发修改 if (CONCURRENT_MODIFICATION_EXCEPTIONS && mSize > 0) { throw new ConcurrentModificationException(); } } // 清除所有items,但不减少ArrayMap已开辟空间 public void erase() { if (mSize > 0) { final int N = mSize<<1; final Object[] array = mArray; for (int i=0; i<N; i++) { array[i] = null; } mSize = 0; } } // 保证ArrayMap扩容到minimumCapacity个空间 public void ensureCapacity(int minimumCapacity) { final int osize = mSize; if (mHashes.length < minimumCapacity) { final int[] ohashes = mHashes; final Object[] oarray = mArray; // 创建新数组空间 allocArrays(minimumCapacity); // 迁移items到新数组空间 if (mSize > 0) { System.arraycopy(ohashes, 0, mHashes, 0, osize); System.arraycopy(oarray, 0, mArray, 0, osize<<1); } // 释放旧数组空间 freeArrays(ohashes, oarray, osize); } // 检查是否存在并发修改 if (CONCURRENT_MODIFICATION_EXCEPTIONS && mSize != osize) { throw new ConcurrentModificationException(); } } // 检查key是否包含在数组中 @Override public boolean containsKey(Object key) { return indexOfKey(key) >= 0; } // 返回key在集合中的索引 public int indexOfKey(Object key) { return key == null ? indexOfNull() : indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode()); } // 检查value在数组中的索引值 int indexOfValue(Object value) { final int N = mSize*2; final Object[] array = mArray; if (value == null) { // value为空,则查找第一个值为空的索引 for (int i=1; i<N; i+=2) { // 每次递增2,保证索引指到值的位置上 // array[i]匹配null if (array[i] == null) { return i>>1; // 整形值通过右移1位完成除以2的操作,即i/2 } } } else { // value不为空,则查找第一个值匹配的索引 for (int i=1; i<N; i+=2) { // 每次递增2,保证索引指到值的位置上 // array[i]value if (value.equals(array[i])) { return i>>1; // 整形值通过右移1位完成除以2的操作,即i/2 } } } // 集合中没有指定key,返回-1 return -1; } // 检查value是否包含在数组中,此调用会对整个数组进行线性查找 @Override public boolean containsValue(Object value) { return indexOfValue(value) >= 0; } // 根据key从数组中获取对应值,没有对应值则返回null @Override public V get(Object key) { // 根据key算出所在数组的索引值 final int index = indexOfKey(key); // 从索引值取值,若索引值为负数,则返回null return index >= 0 ? (V)mArray[(index<<1)+1] : null; } // 根据key的索引从数组中取key的实例 public K keyAt(int index) { // 根据索引值直接取key return (K)mArray[index << 1]; } // 根据value的索引从数组中取value的实例 public V valueAt(int index) { // 根据索引值直接取value return (V)mArray[(index << 1) + 1]; } // 根据key的索引在数组中设置key的新值,如果此索引已有旧值,则作为结果返回 public V setValueAt(int index, V value) { index = (index << 1) + 1; // 获取旧元素 V old = (V)mArray[index]; // 存入新元素 mArray[index] = value; // 返回旧元素 return old; } // 检查数组是否为空 @Override public boolean isEmpty() { return mSize <= 0; } // 向ArrayMap中存入新的<Key, value>,如果key有对应的旧value,则旧value会被替换 @Override public V put(K key, V value) { // 原数组元素数量 final int osize = mSize; // 根据变量key算出来的哈希值 final int hash; // 索引值 int index; // key为空则搜索值为空的索引 if (key == null) { hash = 0; index = indexOfNull(); } else { // 通过key计算索引 hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode(); // key和hash查找索引 index = indexOf(key, hash); } if (index >= 0) { // 命中已有item // 已有key在mArray数组的索引 index = (index<<1) + 1; // 取出旧值 final V old = (V)mArray[index]; // 数组相同位置存入新值 mArray[index] = value; // 返回旧值 return old; } index = ~index; if (osize >= mHashes.length) { // osize >= BASE_SIZE*2 的大小为 osize+(osize>>1) // BASE_SIZE*2 > osize >= BASE_SIZE 的大小为 BASE_SIZE*2 // osize < BASE_SIZE 的大小为 BASE_SIZE final int n = osize >= (BASE_SIZE*2) ? (osize+(osize>>1)) : (osize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE); final int[] ohashes = mHashes; final Object[] oarray = mArray; allocArrays(n); // 检查是否存在并发修改 if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) { throw new ConcurrentModificationException(); } // ohashes元素全部复制到mHashes // oarray元素全部复制到mArray if (mHashes.length > 0) { System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length); System.arraycopy(oarray, 0, mArray, 0, oarray.length); } // 释放ohashes和oarray的空间 freeArrays(ohashes, oarray, osize); } // 新存入key-value需插入到原有元素之间 if (index < osize) { System.arraycopy(mHashes, index, mHashes, index + 1, osize - index); System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1); } // 检查是否存在并发修改 if (CONCURRENT_MODIFICATION_EXCEPTIONS) { if (osize != mSize || index >= mHashes.length) { throw new ConcurrentModificationException(); } } // 数组已创建完毕,且原有元素位置都移动好,则在指定位置放入新key-value mHashes[index] = hash; mArray[index<<1] = key; mArray[(index<<1)+1] = value; // 以保存元素数量递增 mSize++; return null; } // 不验证数组是否有足够空间插入key-value public void append(K key, V value) { int index = mSize; final int hash = key == null ? 0 : (mIdentityHashCode ? System.identityHashCode(key) : key.hashCode()); if (index >= mHashes.length) { throw new IllegalStateException("Array is full"); } if (index > 0 && mHashes[index-1] > hash) { RuntimeException e = new RuntimeException("here"); e.fillInStackTrace(); put(key, value); return; } // 空间足够,正常插入key-value mSize = index+1; // 存入哈希值 mHashes[index] = hash; index <<= 1; // 存入key-value mArray[index] = key; mArray[index+1] = value; } // 使用append()会导致array maps失效,尤其是同一个key出现了多次 // 此方法验证array map是有效的,并在出现问题时抛出IllegalArgumentException public void validate() { final int N = mSize; if (N <= 1) { // There can't be dups. return; } int basehash = mHashes[0]; int basei = 0; for (int i=1; i<N; i++) { int hash = mHashes[i]; if (hash != basehash) { basehash = hash; basei = i; continue; } // 向前检查看key是否出现重复 final Object cur = mArray[i<<1]; for (int j=i-1; j>=basei; j--) { final Object prev = mArray[j<<1]; if (cur == prev) { throw new IllegalArgumentException("Duplicate key in ArrayMap: " + cur); } if (cur != null && prev != null && cur.equals(prev)) { throw new IllegalArgumentException("Duplicate key in ArrayMap: " + cur); } } } } // 把array变量中的所有键值对存入实例中 public void putAll(ArrayMap<? extends K, ? extends V> array) { // 获取当前实例array长度 final int N = array.mSize; // 确保当前ArrayMap有足够空间保存array的所有元素 ensureCapacity(mSize + N); if (mSize == 0) { if (N > 0) { System.arraycopy(array.mHashes, 0, mHashes, 0, N); System.arraycopy(array.mArray, 0, mArray, 0, N<<1); mSize = N; } } else { for (int i=0; i<N; i++) { put(array.keyAt(i), array.valueAt(i)); } } } // 从ArrayMap中移除该存在的key和对应的value @Override public V remove(Object key) { // 根据key查找对应索引 final int index = indexOfKey(key); // 索引值大于0表示key存在 if (index >= 0) { // 移除该key return removeAt(index); } // key没有找到,返回null return null; } // 根据给定的index移除目标键值对,方法结果返回键值对的值 public V removeAt(int index) { final Object old = mArray[(index << 1) + 1]; final int osize = mSize; final int nsize; if (osize <= 1) { // Now empty. freeArrays(mHashes, mArray, osize); mHashes = EmptyArray.INT; mArray = EmptyArray.OBJECT; nsize = 0; } else { nsize = osize - 1; // mHashes.length > 8 && mSize < mHashes.length/3 if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) { // 缩小数组的空间,并且大小不低于BASE_SIZE*2 final int n = osize > (BASE_SIZE*2) ? (osize + (osize>>1)) : (BASE_SIZE*2); final int[] ohashes = mHashes; final Object[] oarray = mArray; allocArrays(n); // 出现并发修改,抛出异常 if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) { throw new ConcurrentModificationException(); } if (index > 0) { // 从ohashes拷贝[0, index)到mHashes System.arraycopy(ohashes, 0, mHashes, 0, index); // 从oarray拷贝[0,index << 1)到mArray System.arraycopy(oarray, 0, mArray, 0, index << 1); } if (index < nsize) { // 从ohashes拷贝剩余items到mHashes System.arraycopy(ohashes, index + 1, mHashes, index, nsize - index); // 从oarray拷贝剩余items到mArray System.arraycopy(oarray, (index + 1) << 1, mArray, index << 1, (nsize - index) << 1); } } else { if (index < nsize) { // mHashes数组,index后的hash逐个前移一位 System.arraycopy(mHashes, index + 1, mHashes, index, nsize - index); // mArray数组,(index + 1) << 1后的元素前移 System.arraycopy(mArray, (index + 1) << 1, mArray, index << 1, (nsize - index) << 1); } // mArray最后两个空间置空 mArray[nsize << 1] = null; mArray[(nsize << 1) + 1] = null; } } // 检查是否存在并发修改 if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) { throw new ConcurrentModificationException(); } mSize = nsize; return (V)old; } // 返回ArrayMap保存的键值对数量 @Override public int size() { return mSize; } // 检查元素和本实例是否等同 @Override public boolean equals(Object object) { // 为同一个对象返回false if (this == object) { return true; } // 先检查对象object是否为Map的子类,不是则无法进行比较,返回false if (object instanceof Map) { Map<?, ?> map = (Map<?, ?>) object; // 先检查元素数量,以便快速确认失败并返回false if (size() != map.size()) { return false; } // 类型一直,数量一样,需要逐个对比元素是否一样 try { for (int i=0; i<mSize; i++) { K key = keyAt(i); V mine = valueAt(i); Object theirs = map.get(key); if (mine == null) { if (theirs != null || !map.containsKey(key)) { return false; } } else if (!mine.equals(theirs)) { return false; } } } catch (NullPointerException ignored) { return false; } catch (ClassCastException ignored) { // 比较过程中元素类型转换抛出异常,返回false return false; } // 两个map的元素完全相同,返回true return true; } // 两个map的元素不完全相同,返回false return false; }
七、集合操作
private MapCollections<K, V> getCollection() { if (mCollections == null) { mCollections = new MapCollections<K, V>() { @Override protected int colGetSize() { return mSize; } @Override protected Object colGetEntry(int index, int offset) { return mArray[(index<<1) + offset]; } @Override protected int colIndexOfKey(Object key) { return indexOfKey(key); } @Override protected int colIndexOfValue(Object value) { return indexOfValue(value); } @Override protected Map<K, V> colGetMap() { return ArrayMap.this; } @Override protected void colPut(K key, V value) { put(key, value); } @Override protected V colSetValue(int index, V value) { return setValueAt(index, value); } @Override protected void colRemoveAt(int index) { removeAt(index); } @Override protected void colClear() { clear(); } }; } return mCollections; } // 检查ArrayMap是否包含collection中全部元素 public boolean containsAll(Collection<?> collection) { return MapCollections.containsAllHelper(this, collection); } // 把map变量中的所有键值对存入实例中 @Override public void putAll(Map<? extends K, ? extends V> map) { ensureCapacity(mSize + map.size()); for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) { put(entry.getKey(), entry.getValue()); } } // 移除ArrayMap中与collection共有的元素 public boolean removeAll(Collection<?> collection) { return MapCollections.removeAllHelper(this, collection); } // 仅保留ArrayMap中与collection共有的元素 public boolean retainAll(Collection<?> collection) { return MapCollections.retainAllHelper(this, collection); } // 返回一个包含ArrayMap所有键值对的集合 @Override public Set<Map.Entry<K, V>> entrySet() { return getCollection().getEntrySet(); } // 返回一个包含ArrayMap所有key的集合 @Override public Set<K> keySet() { return getCollection().getKeySet(); } // 返回一个包含ArrayMap所有value的集合 @Override public Collection<V> values() { return getCollection().getValues(); }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 【源码阅读】AndPermission源码阅读
- ReactNative源码解析-初识源码
- 【源码阅读】Gson源码阅读
- Spring源码系列:BeanDefinition源码解析
- istio 源码 – Citadel 源码分析 (原创)
- istio 源码 – pilot 源码分析(原创)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Google模式
Eric Schmidt、Jonathan Rosenberg / 李芳齡 / 天下雜誌出版社 / 2014-11-7 / TWD 420.00
上市即登紐約時報暢銷書、Amazon科技經營排行榜TOP1 未上市即售出美、英、德、日、荷等12國版權 Google創辦人Larry Page專文推薦 第一本由Google領導團隊人首度公開的企業內部運作與思維 Google董事會執行主席艾力克.施密特獨家揭露 Google從崛起到稱霸超過10年的管理與工作秘笈, 以及如何吸引21世紀最搶手的人才-智慧創做者(S......一起来看看 《Google模式》 这本书的介绍吧!