欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

荐 灵魂一问,Android中有代替HashMap的方法吗?

程序员文章站 2022-07-02 23:12:34
什么是HashMap?简单的说就是用来存放映射关系数据的一个集合工具,就是一个Key,对应一个Value,通过指定Key,可以查找对应Value。他在JDK1.7和JDK1.8或以后的实现方法不同,1.7是数组+链表,1.8则是数组+链表+红黑树结构,(当链表长度大于8,转为红黑树)。当然还有很多不同的地方。为什么要代替HashMap?就像我们生活中一样,一个东西被替代,无非就是新的更好而已,而且具有旧的所有功能。那我们为什么有理由不去使用他呢?在Android中可以代替HashMap的类是Spar...

什么是HashMap?

简单的说就是用来存放映射关系数据的一个集合工具,就是一个Key,对应一个Value,通过指定Key,可以查找对应Value。他在JDK1.7和JDK1.8或以后的实现方法不同,1.7是数组+链表,1.8则是数组+链表+红黑树结构,(当链表长度大于8,转为红黑树)。当然还有很多不同的地方。

为什么要代替HashMap?

就像我们生活中一样,一个东西被替代,无非就是新的更好而已,而且具有旧的所有功能。那我们为什么有理由不去使用他呢?

在Android中可以代替HashMap的类是SparseArray,他比HashMap更节省内存,因为它避免了自动装箱操作,也就是int转为Integer类型,哦忘了说了,SparseArray的Key只能为int,也就是当我们只有在key是int的时候才可以使用SparseArray,其实还有SparseIntArray、SparseLongArray、SparseBooleanArray类。那我的key是其他的类型时候呢?当然还有其他办法,那就是ArrayMap。

还有就是SparseArray并不像HashMap采用一维数组+单链表结构,而是采用两个一维数组,一个是存储key(int类型),一个是存在value。

private int[] mKeys;

private Object[] mValues;

怎么使用SparseArray?

使用他其实和HashMap类似,实例化、put…,SparseArray如果不指定容量,默认是10大小。

 public SparseArray() {
     this(10);
 }

插入

SparseArray<Book> bookSparseArray = new SparseArray<>();
bookSparseArray.put(1,new Book("武林秘籍"));
bookSparseArray.put(4,new Book("葵花宝典"));
bookSparseArray.put(2,new Book("十八掌"));
Log.i("TAG", "onCreate: "+bookSparseArray.get(2).getName());

输出:

 I/TAG: onCreate: 十八掌

但是SparseArray还提供了一个append方法,也可以用来添加,

bookSparseArray.put(1,new Book("武林秘籍"));
bookSparseArray.put(4,new Book("葵花宝典"));
bookSparseArray.put(2,new Book("十八掌"));
bookSparseArray.append(3,new Book("九阳真经"));
Log.i("TAG", "onCreate: "+bookSparseArray.get(3).getName());

从源码第一句可以看出,如果数量不为0,并且新增的key小于等于mKeys[mSize - 1],就调用put方法,也就是如果新增的key大于现有的所有键时进行优化。

public void append(int key, E value) {
    if (mSize != 0 && key <= mKeys[mSize - 1]) {
        put(key, value);
        return;
    }
    if (mGarbage && mSize >= mKeys.length) {
        gc();
    }
    mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
    mValues = GrowingArrayUtils.append(mValues, mSize, value);
    mSize++;
}

和HashMap不同的是,SparseArray提供了valueAt、keyAt用来查找指定索引位置的值、指定索引位置的key是多少。

 SparseArray<Book> bookSparseArray = new SparseArray<>();
 bookSparseArray.put(1,new Book("武林秘籍"));
 bookSparseArray.put(4,new Book("葵花宝典"));
 bookSparseArray.put(2,new Book("十八掌"));
 bookSparseArray.append(3,new Book("九阳真经"));
 Log.i("TAG", "onCreate: "+bookSparseArray.valueAt(2).getName());
 Log.i("TAG", "onCreate: "+bookSparseArray.keyAt(3));

输出:

I/TAG: onCreate: 九阳真经
I/TAG: onCreate: 4

输出的结果是不是意想不到?其实在put的时候做了一些处理,SparseArray会根据Key自动排序(生序)。
荐
                                                        灵魂一问,Android中有代替HashMap的方法吗?
荐
                                                        灵魂一问,Android中有代替HashMap的方法吗?

删除

删除为我们提供了removeAt、remove、delete,分为是删除指定索引位置的数据,删除指定key、删除指定key。remove和delete是等价的,都一样。

 public void remove(int key) {
     delete(key);
 }

还有一个是移除指定区间的removeAtRange。

 SparseArray<Book> bookSparseArray = new SparseArray<>();
 bookSparseArray.put(1,new Book("武林秘籍"));
 bookSparseArray.put(4,new Book("葵花宝典"));
 bookSparseArray.put(2,new Book("十八掌"));
 bookSparseArray.append(3,new Book("九阳真经"));
 Log.i("TAG", "onCreate: "+bookSparseArray.valueAt(2).getName());
 bookSparseArray.remove(2);
 Log.i("TAG", "onCreate: "+bookSparseArray.valueAt(2).getName());
 bookSparseArray.removeAtRange(0,bookSparseArray.size());
 Log.i("TAG", "onCreate: "+bookSparseArray.size());

输出

I/TAG: onCreate: 九阳真经
I/TAG: onCreate: 葵花宝典
I/TAG: onCreate: 0

获取

我们除了根据指定key获取对应值,get方法还有一个重载方法,这个方法提供了当key不存在的时候返回的默认值。

 public E get(int key, E valueIfKeyNotFound) {
     int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
     if (i < 0 || mValues[i] == DELETED) {
         return valueIfKeyNotFound;
     } else {
         return (E) mValues[i];
     }
 }
 SparseArray<Book> bookSparseArray = new SparseArray<>();
 bookSparseArray.put(1,new Book("武林秘籍"));
 bookSparseArray.put(4,new Book("葵花宝典"));
 bookSparseArray.put(2,new Book("十八掌"));
 bookSparseArray.append(3,new Book("九阳真经"));
 Book valueBook = bookSparseArray.get(5, new Book("空手套白狼"));
 Log.i("TAG", "onCreate: "+valueBook.getName());

设置指定索引位置的值

SparseArray<Book> bookSparseArray = new SparseArray<>();
bookSparseArray.put(1,new Book("武林秘籍"));
bookSparseArray.put(4,new Book("葵花宝典"));
bookSparseArray.put(2,new Book("十八掌"));
bookSparseArray.append(3,new Book("九阳真经"));
Log.i("TAG", "onCreate: "+bookSparseArray.valueAt(2).getName());
bookSparseArray.setValueAt(2,new Book("听风逝夜"));
Log.i("TAG", "onCreate: "+bookSparseArray.valueAt(2).getName());

输出

 I/TAG: onCreate: 九阳真经
 I/TAG: onCreate: 听风逝夜

二分法

在SparseArray中用到了二分法,用来查找key的索引位置。二分法查找针对的是一个有序的数据集合,每次通过与区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为0。

下面是ContainerHelpers类下的binarySearch方法实现,当然这个类我们访问不到。但是我们可以使用Collections.binarySearch或者Arrays.binarySearch。

static int binarySearch(int[] array, int size, int value) {
    int lo = 0;
    int hi = size - 1;
    while (lo <= hi) {
        final int mid = (lo + hi) >>> 1;
        final int midVal = array[mid];
        if (midVal < value) {
            lo = mid + 1;
        } else if (midVal > value) {
            hi = mid - 1;
        } else {
            return mid; 
        }
    }
    return ~lo;  
}
 int[] data ={1,3,4,6,7,9};
 Log.i("TAG", "2的索引位置: "+binarySearch(data,data.length,2));
 Log.i("TAG", "1的索引位置: "+binarySearch(data,data.length,1));
 Log.i("TAG", "9的索引位置: "+binarySearch(data,data.length,9));

输出如下,如果找不到,是返回负数的,这个负数也是具有意义的,称之为插入点,插入点值就是第一个比key大的元素在数组中的位置索引,而且这个位置索引从1开始。

 I/TAG: 2的索引位置: -2
 I/TAG: 1的索引位置: 0
 I/TAG: 9的索引位置: 5

对于上面数据,如果我们查找10,那么会返回-7。或者大于9的数都会返回-7。

本文地址:https://blog.csdn.net/HouXinLin_CSDN/article/details/107288071