Android - ArrayMap

2019-09-26  本文已影响0人  改名_f64e

ArrayMap 和 HashMap 区别

ArrayMap源码 - 重要字段

//默认创建数组的长度
private static final int BASE_SIZE = 4;
//数据释放时,缓存的累计次数(size == 4,或者size==8的情况下释放数组会用到缓存)
private static final int CACHE_SIZE = 10;
//生成空的ArrayMap
public static final ArrayMap EMPTY = new ArrayMap<>(-1);
static final int[] EMPTY_IMMUTABLE_INTS = new int[0];
//size == 4时,缓存的数组
static Object[] mBaseCache;
static int mBaseCacheSize;
//size == 8时,缓存的数组
static Object[] mTwiceBaseCache;
static int mTwiceBaseCacheSize;
//生成HashCoe()的方法
final boolean mIdentityHashCode;
//存放Key HashCode()的值的数组
int[] mHashes;
//存放Key-Value 值的数组,长度是mHashes的2倍
Object[] mArray;
//实际的数据存储长度
int mSize;

ArrayMap源码 - mHashes 和 mArray 的关系图

3768281-1af0108b942ea976 (1).jpg

ArrayMap源码 - 构造方法

  public ArrayMap() {
    this(0, false);
  }
  public ArrayMap(int capacity) {
    this(capacity, false);
  }
  public ArrayMap(int capacity, boolean identityHashCode) {
    //HashCode的生成方式
    //True : System.identityHashCode(key)
    //False : key.hashCode()
    mIdentityHashCode = identityHashCode;
    if (capacity < 0) {
      //空的int[0] 数组
      mHashes = EMPTY_IMMUTABLE_INTS;
      mArray = EmptyArray.OBJECT;
    } else if (capacity == 0) {
      mHashes = EmptyArray.INT;
      mArray = EmptyArray.OBJECT;
    } else {
      //根据大小进行扩容
      allocArrays(capacity);
    }
    mSize = 0;
  }
  private void allocArrays(final int size) {
    if (mHashes == EMPTY_IMMUTABLE_INTS) {
      throw new UnsupportedOperationException("ArrayMap is immutable");
    }
    //BASE_SIZE 默认值=4,这里判断size == 8时候
    if (size == (BASE_SIZE*2)) {
      synchronized (ArrayMap.class) {
        if (mTwiceBaseCache != null) {
          //获取缓存的数组
          final Object[] array = mTwiceBaseCache;
          //数据快速赋值给当前使用的Key-Value数组
          mArray = array;
          // 这里的赋值可以查看freeArrays()中size == 8的情况
          mTwiceBaseCache = (Object[])array[0];
          mHashes = (int[])array[1];
          array[0] = array[1] = null;
          mTwiceBaseCacheSize--;
          if (DEBUG) Log.d(TAG, "Retrieving 2x cache " + mHashes
              + " now have " + mTwiceBaseCacheSize + " entries");
          return;
        }
      }
      //BASE_SIZE 默认值 = 4,这里判断size == 4 的时候
    } else if (size == BASE_SIZE) {
      synchronized (ArrayMap.class) {
        if (mBaseCache != null) {
          final Object[] array = mBaseCache;
          mArray = array;
          mBaseCache = (Object[])array[0];
          mHashes = (int[])array[1];
          array[0] = array[1] = null;
          mBaseCacheSize--;
          if (DEBUG) Log.d(TAG, "Retrieving 1x cache " + mHashes
              + " now have " + mBaseCacheSize + " entries");
          return;
        }
      }
    }
    //如果Size > 8 ,直接创建新的数组
    mHashes = new int[size];
    mArray = new Object[size<<1];
  }
  //释放数组数据
  private static void freeArrays(final int[] hashes, final Object[] array, final int size) {
    //hashes : 存储HashCode()的数组
    //array : 存储Key-Value的数组
    if (hashes.length == (BASE_SIZE*2)) {
      synchronized (ArrayMap.class) {
        //CACHE_SIZE = 10(常量值)
        if (mTwiceBaseCacheSize < CACHE_SIZE) {
          //Key-Value 的数组第一个值 = mTwiceBaseCache
          //Key-Value 的数组第二个值 = hashes
          array[0] = mTwiceBaseCache;
          array[1] = hashes;
          //循环遍历,数组上剩余的数据赋值为null
          for (int i=(size<<1)-1; i>=2; i--) {
            array[i] = null;
          }
          //临时数据赋值给缓存数组
          mTwiceBaseCache = array;
          //缓存Size++
          mTwiceBaseCacheSize++;
          if (DEBUG) Log.d(TAG, "Storing 2x cache " + array
              + " now have " + mTwiceBaseCacheSize + " entries");
        }
      }
    } else if (hashes.length == BASE_SIZE) {
      synchronized (ArrayMap.class) {
        if (mBaseCacheSize < CACHE_SIZE) {
          array[0] = mBaseCache;
          array[1] = hashes;
          for (int i=(size<<1)-1; i>=2; i--) {
            array[i] = null;
          }
          mBaseCache = array;
          mBaseCacheSize++;
          if (DEBUG) Log.d(TAG, "Storing 1x cache " + array
              + " now have " + mBaseCacheSize + " entries");
        }
      }
    }
  }

扩容流程 :
  size == (BASE_SIZE*2) 和 size == BASE_SIZE 需要结合freeArrays()进行分析
缓存作用 :
  在数据量较小的时候快速的复用原来的数据,不需要使用System.Copy...()

ArrayMap源码 - put

  @Override
  public V put(K key, V value) {
    //获取当前数据的长度
    final int osize = mSize;
    //Key的Hash值
    final int hash;
    //Key的Index值
    int index;
    if (key == null) {//Key == null时
      hash = 0;
      //查找null的index值,具体逻辑可以参考get()部分,大部分逻辑相同
      //1.if mSize == 0,index = ~0
      //2.binarySearchHashes(mHashes, mSize, 0) 二分法查找数组中数据Index,Index<0,直接返回Index
      //3.if null == mArray[index<<1],通过Index查找Key-Value数组中的Value,Value==Null,直接返回Index
      //4.以Index为中心,mHashes的两边分开查找
        //mHashes[Index] == 0&&null == mArray[Index << 1],直接返回Index
      index = indexOfNull();
    } else {
      //生成Key的HashCode()值
      hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();
      //查找Key HashCode()在mHashes的位置
      index = indexOf(key, hash);
    }
    //Index >=0 表示mHashes中存在这个数据,直接修改Key-Value数组中Value的值,并返回旧Value
    if (index >= 0) {
      index = (index<<1) + 1;
      final V old = (V)mArray[index];
      mArray[index] = value;
      return old;
    }

    //~index :  表示数据取反,例子:index = -11,~index = 10
    index = ~index;
    //当前数据的长度>=HashCode()数组长度
    if (osize >= mHashes.length) {
      //计算扩容大小,>=8 : 扩容为原来1.5倍,>=4 : 扩容为8,否则 : 扩容为4
      final int n = osize >= (BASE_SIZE*2) ? (osize+(osize>>1))
          : (osize >= 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 (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
        throw new ConcurrentModificationException();
      }

      if (mHashes.length > 0) {
        if (DEBUG) Log.d(TAG, "put: copy 0-" + osize + " to 0");
        //数组复制
        System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
        System.arraycopy(oarray, 0, mArray, 0, oarray.length);
      }
      //释放临时数组
      freeArrays(ohashes, oarray, osize);  
    }
    //如果index小于size长度,表示要在数组中间插入数据,此时需要移动数组数据(因为数据是有序排列)
    if (index < osize) {
      if (DEBUG) Log.d(TAG, "put: move " + index + "-" + (osize-index)
          + " to " + (index+1));
      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();
      }
    }
    //数据赋值
    mHashes[index] = hash;
    mArray[index<<1] = key;
    mArray[(index<<1)+1] = value;
    mSize++;
    return null;
  }

ArrayMap源码 - get

  @Override
  public V get(Object key) {
    final int index = indexOfKey(key);
    return index >= 0 ? (V)mArray[(index<<1)+1] : null;
  }
  public int indexOfKey(Object key) {
    return key == null ? indexOfNull()
        : indexOf(key, mIdentityHashCode ? 
          System.identityHashCode(key) : key.hashCode());
  }
  //indexOf()和indexOfNull()的逻辑一样
  int indexOf(Object key, int hash) {
    // 获取当前数据的长度
    final int N = mSize;
    //长度==0,直接返回-1,~0 = -1
    if (N == 0) {
      return ~0;
    }
    //通过二分法查找mHashes数组中key的Hash的index
    int index = binarySearchHashes(mHashes, N, hash);
    //小于 0 表示mHashes数组中不存在这个Key
    if (index < 0) {
      return index;
    }
    // 如果在Key-Value数组中找到对应的Key,并相同,返回Index
    if (key.equals(mArray[index<<1])) {
      return index;
    }
    //此时的index!=0,index>0,表示在mHashes中发生了Key的hash碰撞
    //从碰撞的index开始,向后查找hash相同并且key相同的index值
    int end;
    for (end = index + 1; end < N && mHashes[end] == hash; end++) {
      if (key.equals(mArray[end << 1])) return end;
    }
    //向前查找
    for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {
      if (key.equals(mArray[i << 1])) return i;
    }
    //如果前后都没有找到,返回~end,end = index +1 ,~end = ~(index + 1)
    return ~end;
  }

ArrayMap源码 - remove

  @Override
  public V remove(Object key) {
      //这里查看get()部分
      final int index = indexOfKey(key);
      if (index >= 0) {
          return removeAt(index);
      }
      return null;
  }
  public V removeAt(int index) {
    //通过Key-Value数组获取Value 的值
    final Object old = mArray[(index << 1) + 1];
    //当前数据的长度
    final int osize = mSize;
    final int nsize;
    if (osize <= 1) {
      // Now empty.
      if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
      //释放所有的数组数据
      freeArrays(mHashes, mArray, osize);
      mHashes = EmptyArray.INT;
      mArray = EmptyArray.OBJECT;
      nsize = 0;
    } else {
      //数据remove后数组的长度
      nsize = osize - 1;
      //如果mHashes长度 >=8 && mSize (实际数据长度) < mHashes.length/3 (3分之一)
      if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {
        //准备缩小数组的长度,具体逻辑 :
        //假如当前osize = mSize = 10,那么 n = 15
        //在方法结束时 mSize = nsize = 9(刚才-1)
        //下次再次执行这里是osize = mSize = 9,那么 n = 13,所以在缩小
        final int n = osize > (BASE_SIZE*2) ? (osize + (osize>>1)) : (BASE_SIZE*2);

        if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to " + n);
        //创建临时数组
        final int[] ohashes = mHashes;
        final Object[] oarray = mArray;
        //对数组进行缩小,虽然调用的是扩容方法,但是值在变小
        allocArrays(n);

        if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
          throw new ConcurrentModificationException();
        }
        //数据从新复制到新数组
        if (index > 0) {
          if (DEBUG) Log.d(TAG, "remove: copy from 0-" + index + " to 0");
          System.arraycopy(ohashes, 0, mHashes, 0, index);
          System.arraycopy(oarray, 0, mArray, 0, index << 1);
        }
        if (index < nsize) {
          if (DEBUG) Log.d(TAG, "remove: copy from " + (index+1) + "-" + nsize
              + " to " + index);
          System.arraycopy(ohashes, index + 1, mHashes, index, nsize - index);
          System.arraycopy(oarray, (index + 1) << 1, mArray, index << 1,
              (nsize - index) << 1);
        }
      } else {
        //假如mSize = 10,nsize = 9,index < 9
        if (index < nsize) {
          if (DEBUG) Log.d(TAG, "remove: move " + (index+1) + "-" + nsize
              + " to " + index);
          //数据直接重新复制(把index后面的数据复制到前面来,数组中最后一个数据为Null)
          System.arraycopy(mHashes, index + 1, mHashes, index, nsize - index);
          System.arraycopy(mArray, (index + 1) << 1, mArray, index << 1,
              (nsize - index) << 1);
        }
        mArray[nsize << 1] = null;
        mArray[(nsize << 1) + 1] = null;
      }
    }
    if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
      throw new ConcurrentModificationException();
    }
    //重新赋值长度
    mSize = nsize;
    //返回旧Value
    return (V)old;
  }

上一篇 下一篇

猜你喜欢

热点阅读