返回

ArrayMap 揭秘:替代 HashMap 的强悍利器

Android

前言

在 Android 开发中,HashMap 是一种常用的数据结构,用于存储键值对。然而,当数据量较小时(例如几百个),HashMap 可能不是最优选择。为了解决这个问题,Android SDK 提供了一个更适合小数据量的替代方案——ArrayMap。

ArrayMap 概述

ArrayMap 是一个基于数组实现的映射表,它继承自 HashMap,但采用了不同的存储结构和算法。与 HashMap 相比,ArrayMap 具有以下特点:

  • 更快的查找速度: ArrayMap 使用数组来存储键值对,因此查找键值对的时间复杂度为 O(1),而 HashMap 使用哈希表,查找时间复杂度为 O(log n)。当数据量较小(几百个或更少)时,ArrayMap 的查找速度优势非常明显。
  • 更小的内存占用: ArrayMap 使用数组存储键值对,因此内存占用更小。HashMap 使用哈希表存储键值对,哈希表需要额外的空间来存储哈希值,因此内存占用更大。
  • 更简单的实现: ArrayMap 的实现比 HashMap 更简单,因为它使用数组而不是哈希表。这意味着更少的代码量和更低的维护成本。

ArrayMap 原理

ArrayMap 的基本原理是使用数组存储键值对。它将键值对存储在一个二维数组中,其中第一列存储键,第二列存储值。当需要查找一个键值对时,ArrayMap 会先在第一列中搜索键,然后在找到键后返回相应的键值对。

为了提高查找效率,ArrayMap 使用二分查找算法。二分查找算法是一种快速查找算法,它将数组分成两半,然后根据键的值来判断键值对位于哪一半。这样,就可以快速缩小查找范围,直到找到键值对。

ArrayMap 源码分析

ArrayMap 的实现位于 android.util.ArrayMap 类中。该类提供了许多方法来操作 ArrayMap,包括 put、get、remove 等。下面我们通过源码分析来了解 ArrayMap 的内部实现机制。

public class ArrayMap<K, V> extends Map<K, V> {

    private static final boolean DEBUG = false;

    private static final String TAG = "ArrayMap";

    // 默认容量
    private static final int BASE_SIZE = 4;

    // 负载因子
    private static final float LOAD_FACTOR = 0.8f;

    // 数组
    private Object[] mArray;

    // 键的索引
    private int[] mHashes;

    // 当前数组大小
    private int mSize;

    // 键值对数量
    private int mCapacity;

    // 修改次数
    private int mModCount;

    // 初始化
    public ArrayMap() {
        this(BASE_SIZE);
    }

    // 根据容量初始化
    public ArrayMap(int capacity) {
        if (capacity == 0) {
            throw new IllegalArgumentException("Capacity must be positive.");
        }
        mCapacity = capacity;
        mHashes = new int[capacity];
        mArray = new Object[capacity * 2];
        mSize = 0;
    }

    // 获取值
    @Override
    public V get(Object key) {
        int index = indexOfKey(key);
        if (index < 0) {
            return null;
        }
        return (V) mArray[index * 2 + 1];
    }

    // 设置值
    @Override
    public V put(K key, V value) {
        int index = indexOfKey(key);
        if (index < 0) {
            index = insertKey(key, value);
        } else {
            V oldValue = (V) mArray[index * 2 + 1];
            mArray[index * 2 + 1] = value;
            return oldValue;
        }
        return null;
    }

    // 删除值
    @Override
    public V remove(Object key) {
        int index = indexOfKey(key);
        if (index < 0) {
            return null;
        }
        V oldValue = (V) mArray[index * 2 + 1];
        removeAt(index);
        return oldValue;
    }

    // 扩容
    private void allocArrays(int size) {
        Object[] oldArray = mArray;
        int[] oldHashes = mHashes;
        int oldCapacity = mCapacity;

        int newCapacity = (size > (3 * mCapacity) / 4) ? size : (mCapacity << 1);
        if (newCapacity < size) {
            newCapacity = size;
        }
        mHashes = new int[newCapacity];
        mArray = new Object[newCapacity * 2];
        mCapacity = newCapacity;

        if (mSize > 0) {
            for (int i = 0; i < mSize; i++) {
                int index = i * 2;
                Object key = oldArray[index];
                Object value = oldArray[index + 1];
                int hash = key == null ? 0 : key.hashCode();
                int newIndex = indexOf(hash, key, newCapacity);
                mHashes[newIndex] = hash;
                mArray[newIndex * 2] = key;
                mArray[newIndex * 2 + 1] = value;
            }
        }
    }

    // 插入键值对
    private int insertKey(K key, V value) {
        int hash = key == null ? 0 : key.hashCode();
        int index = indexOf(hash, key, mCapacity);
        mHashes[index] = hash;
        mArray[index * 2] = key;
        mArray[index * 2 + 1] = value;
        mSize++;
        if (mSize > (LOAD_FACTOR * mCapacity)) {
            allocArrays(mSize * 2);
        }
        return index;
    }

    // 删除键值对
    private void removeAt(int index) {
        if (mSize <= 1) {
            clear();
        } else {
            mSize--;
            if (mHashes[index] == mHashes[mSize]) {
                mArray[index * 2] = mArray[mSize * 2];
                mArray[index * 2 + 1] = mArray[mSize * 2 + 1];
            } else {
                int keyIndex = indexOfKey(mArray[index * 2], mSize);
                if (keyIndex == index) {
                    return;
                }
                mArray[index * 2] = mArray[keyIndex * 2];
                mArray[index * 2 + 1] = mArray[keyIndex * 2 + 1];
                mArray[keyIndex * 2] = null;
                mArray[keyIndex * 2 + 1] = null;
            }
            mArray[mSize * 2] = null;
            mArray[mSize * 2 + 1] = null;
        }
        mModCount++;
    }

    // 获取键的索引
    private int indexOfKey(Object key) {
        int hash = key == null ? 0 : key.hashCode();
        for (int i = 0; i < mSize; i++) {
            if (mHashes[i] == hash) {
                Object arrayKey = mArray[i * 2];
                if (key == arrayKey || (key != null && key.equals(arrayKey))) {
                    return i;
                }
            }
        }
        return -1;
    }

    // 获取哈希值