Android ArrayMap源码分析

文章目录

Android ArrayMap源码分析

概述

  • ArrayMap 是 Android 提供的一种轻量级的 Map 实现,在一定程度上替代 HashMap 的使用。
  • 内部使用数组存储数据:
    • hash数组:存储 key 的哈希值,升序排列
    • Array数组:存储键和值,交替存放:[key1, value1, key2, value2 ,...]
  • 键是有序的,使用二分查找法。
  • 支持空键和空值。
  • 线程不安全。

源码分析

基本属性

java 复制代码
public final class ArrayMap<K, V> implements Map<K, V> {
    // 存储key的哈希值,升序排列
    int[] mHashes; 
    // 存储key和value,交替存放:[key1,value1,key2,value2,....]
    Object[] mArray;
    // 元素数量
    int mSize;
}

构造函数

java 复制代码
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) {
        mHashes = EmptyArray.INT;
        mArray = EmptyArray.OBJECT;
    } else {
        allocArrays(capacity);
    }
    mSize = 0;
}

public ArrayMap(ArrayMap<K, V> map) {
    this();
    if (map != null) {
        putAll(map);
    }
}

put()

使用二分查找法获取位置,如果找到位置则替换旧值,如果没有找到则插入新值,插入操作是需要移动数组。

扩容策略:小于 4 → 扩到 4;4~8 → 扩到 8;大于 8 → 扩 1.5 倍。

java 复制代码
@Override
public V put(K key, V value) {
    final int osize = mSize;
    final int hash;
    int index;

    if (key == null) {
        // 如果key为null则查找null键位置
        hash = 0;
        index = indexOfNull();
    } else {
        // 如果key不为null,则获取key的hash值,使用二分查找法获取位置
        hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();
        index = indexOf(key, hash);
    }

    if (index >= 0) {
        // 如果index存在,则覆盖旧值
        index = (index<<1) + 1;
        final V old = (V)mArray[index];
        mArray[index] = value;
        return old;
    }

    // key不存在,插入新值
    index = ~index;
    if (osize >= mHashes.length) {
        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 (mHashes.length > 0) {
            System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
            System.arraycopy(oarray, 0, mArray, 0, oarray.length);
        }

        // 释放旧数组
        freeArrays(ohashes, oarray, osize);
    }

    // 插入新数据操作
    if (index < osize) {
        System.arraycopy(mHashes, index, mHashes, index + 1, osize - index);
        System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1);
    }
    mHashes[index] = hash;
    mArray[index<<1] = key;
    mArray[(index<<1)+1] = value;
    
    // 更新元素数量
    mSize++;
    
    // 插入新值返回null
    return null;
}

indexOf()

java 复制代码
int indexOf(Object key, int hash) {
    final int N = mSize;

    if (N == 0) {
        return ~0;
    }

    // 通过二分查找法获取位置
    int index = binarySearchHashes(mHashes, N, hash);

    // 未找到
    if (index < 0) {
        return index;
    }

    // hash值相同且key值也相同
    if (key.equals(mArray[index<<1])) {
        return index;
    }

    // 哈希冲突
    int end;
    // 向后搜索
    for (end = index + 1; end < N && mHashes[end] == hash; end++) {
        // << 1是位运算,相当于乘以2
        // 比较key值是否相等
        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;
    }

    return ~end;
}

get()

java 复制代码
public V get(Object key) {
    // 二分查找法获取位置
    final int index = indexOfKey(key);
    // 通过位置获取value值
    return index >= 0 ? (V)mArray[(index<<1)+1] : null;
}

ArrayMap 对比 HashMap、SparseArray

ArrayMap HashMap SparseArray
平台 Android Java Android
键 任意类型 任意类型 必须int
值 任意类型 任意类型 任意类型
是否支持null键 是 是 否
是否支持null值 是 是 是
数据结构 int\[\] mHashes Object\[\] mArray 数组+链表/红黑树 int\[\] mKeys Object\[\] mValues
内存开销 中 高 低
相关推荐
2501_915909062 小时前
Ipa Guard 防护上架,混淆、重签名和回归测试怎么做
android·ios·小程序·https·uni-app·iphone·webview
码点2 小时前
Android ANR 全解析 与 traces 分析实战
android
敲代码的瓦龙3 小时前
Jetpack?lifecycle!!!
android·kotlin
苦瓜花3 小时前
Hilt用使用及原理
android
深度学习04074 小时前
MySQL InnoDB Cluster 部署完整文档
android·mysql·adb
邪修king5 小时前
Re:Linux系统篇(三十七):进程间通信Chapter4:System V 共享内存深度解析:为什么它是最快的 IPC?
android·linux·运维
用户337922545685 小时前
Kiora SDK:在 Android 上组织端侧模型、工具与 A2A 协作
android
洞见前行5 小时前
你在 XML 时代学的渲染优化,进了 Compose 大多不再是重点——Recomposition 才是新的战场
android
ii_best6 小时前
按键精灵手机助手 v5.2.1 实测:inputText 逐字延时 + 调试面板多行复制,安卓脚本开发的两个输入痛点一次解决
android·开发语言·智能手机·自动化·ai编程·按键精灵
hunterandroid6 小时前
OkHttp 源码解析:拦截器链、连接池与缓存策略的设计精髓
android