安卓SparseArray的indexOfValue方法遇到的坑

来源:互联网 发布:centos7下安装mysql 编辑:程序博客网 时间:2024/06/08 00:23

在数据量比较少的情况下使用SparseArray可以提高效率,最近一个项目利用它存储int型数据,利用indexOfValue去获取value的索引,本以为value大小范围可以是int的范围大小,结果不是,数据可以存储但是利用indexOfValue方法得到的索引就是不对返回-1检索不到,特别坑,当value范围是-128到127,indexOfValue才能得到正确的索引,查阅官方文档也没有找到原因,如果有大佬发现原因麻烦指出了,一起交流。解决这个问题可以用SparseIntArray代替,value的值是int的范围通过indexOfValue方法也能获得正确的索引。实验代码如下: 

SparseArray<Integer> abc = new SparseArray<Integer>();int gpuIndex = 0;abc.put(gpuIndex++, 127);abc.put(gpuIndex++, 128);abc.put(gpuIndex++, -128);        int a, a1, a2;        a = a1 = a2 = Integer.MIN_VALUE;        a = abc.indexOfValue(127);        a1 = abc.indexOfValue(128);        a2 = abc.indexOfValue(-128);        Log.i("SparseArray", "SparseArrayIndex127: " + a);        Log.i("SparseArray", "SparseArrayIndex128: " + a1);        Log.i("SparseArray", "SparseArrayIndex-128: " + a2);                SparseIntArray def = new SparseIntArray();        int index = 0;        def.put(index++, 2147483647);        int b = def.indexOfValue(2147483647);        Log.i("SparseIntArray", "SparseIntArrayIndex: " + b);
输出的log日志为:

07-20 16:53:45.611: I/SparseArray(13173): SparseArrayIndex127: 007-20 16:53:45.611: I/SparseArray(13173): SparseArrayIndex128: -107-20 16:53:45.611: I/SparseArray(13173): SparseArrayIndex-128: 207-20 16:53:45.611: I/SparseIntArray(13173): SparseIntArrayIndex: 0

如果大佬知道原因还希望指出来一起讨论!

------------------------------------------------------------------2017.8.9更新----------------------------------------------------------------------------------------------

查看java的int的自动装箱机制发现了问题的原因,是由于自动装箱机制和“==”比较引起的

首先看一下SparseArray的indexOfValue方法源码

 /**     * Returns an index for which {@link #valueAt} would return the     * specified key, or a negative number if no keys map to the     * specified value.     * <p>Beware that this is a linear search, unlike lookups by key,     * and that multiple keys can map to the same value and this will     * find only one of them.     * <p>Note also that unlike most collections' {@code indexOf} methods,     * this method compares values using {@code ==} rather than {@code equals}.     */    public int indexOfValue(E value) {        if (mGarbage) {            gc();        }        for (int i = 0; i < mSize; i++)            if (mValues[i] == value)                return i;        return -1;    }
注释已经提示了是利用“==”来进行比较,比较的是对象引用的地址,而传进来的类型E是是Integer的对象,我们知道在-128至127的数自动装箱时,获得的是同一个对象,而不在这个范围的自动装箱获得的是不同的对象,例子如下:

Integer num1 = 666; Integer num2 = 666; Integer num3 = 88; Integer num4 = 88;

System.out.println("num1==num2: "+(num1==num2));

System.out.println("num3==num4: "+(num3==num4)); 

输出结果:num1==num2: false num3==num4: true 

所以indexOfValue(128)时,128自动装箱成Integer对象,利用“==”与原来put进去的128是不同的对象,所以检索不到,返回-1;

再看SparseIntArray的indexOfValue源码:

    /**     * Returns an index for which {@link #valueAt} would return the     * specified key, or a negative number if no keys map to the     * specified value.     * Beware that this is a linear search, unlike lookups by key,     * and that multiple keys can map to the same value and this will     * find only one of them.     */    public int indexOfValue(int value) {        for (int i = 0; i < mSize; i++)            if (mValues[i] == value)                return i;        return -1;    }
用的也是“==”,但是比较的类型是基本数据类型int,而不是Integer对象,所以能够检索到之前的数据。问题根源解决!

------------------------------------------------------------------------------------------------------------------------------------------------

后记:细节决定成败啊


 

原创粉丝点击