由于网上有朋友对于这个问题已经有了很详细的研究,所以我就不班门弄斧了:

转载于:http://android-performance.com/android/2014/02/10/android-sparsearray-vs-hashmap.html

    http://liuzhichao.com/p/832.html

 

http://www.codes51.com/article/detail_163576.html

源码:

  1 /*
  2  * Copyright (C) 2006 The Android Open Source Project
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 package android.util;
 17 import com.android.internal.util.ArrayUtils;
 18 import com.android.internal.util.GrowingArrayUtils;
 19 import libcore.util.EmptyArray;
 20 /**
 21  * SparseArrays map integers to Objects.  Unlike a normal array of Objects,
 22  * there can be gaps in the indices.  It is intended to be more memory efficient
 23  * than using a HashMap to map Integers to Objects, both because it avoids
 24  * auto-boxing keys and its data structure doesn't rely on an extra entry object
 25  * for each mapping.
 26  *
 27  * <p>Note that this container keeps its mappings in an array data structure,
 28  * using a binary search to find keys.  The implementation is not intended to be appropriate for
 29  * data structures
 30  * that may contain large numbers of items.  It is generally slower than a traditional
 31  * HashMap, since lookups require a binary search and adds and removes require inserting
 32  * and deleting entries in the array.  For containers holding up to hundreds of items,
 33  * the performance difference is not significant, less than 50%.</p>
 34  *
 35  * <p>To help with performance, the container includes an optimization when removing
 36  * keys: instead of compacting its array immediately, it leaves the removed entry marked
 37  * as deleted.  The entry can then be re-used for the same key, or compacted later in
 38  * a single garbage collection step of all removed entries.  This garbage collection will
 39  * need to be performed at any time the array needs to be grown or the the map size or
 40  * entry values are retrieved.</p>
 41  *
 42  * <p>It is possible to iterate over the items in this container using
 43  * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
 44  * <code>keyAt(int)</code> with ascending values of the index will return the
 45  * keys in ascending order, or the values corresponding to the keys in ascending
 46  * order in the case of <code>valueAt(int)</code>.</p>
 47  */
 48 public class SparseArray<E> implements Cloneable {
 49     private static final Object DELETED = new Object();
 50     private boolean mGarbage = false;
 51     private int[] mKeys;
 52     private Object[] mValues;
 53     private int mSize;
 54     /**
 55      * Creates a new SparseArray containing no mappings.
 56      */
 57     public SparseArray() {
 58         this(10);
 59     }
 60     /**
 61      * Creates a new SparseArray containing no mappings that will not
 62      * require any additional memory allocation to store the specified
 63      * number of mappings.  If you supply an initial capacity of 0, the
 64      * sparse array will be initialized with a light-weight representation
 65      * not requiring any additional array allocations.
 66      */
 67     public SparseArray(int initialCapacity) {
 68         if (initialCapacity == 0) {
 69             mKeys = EmptyArray.INT;
 70             mValues = EmptyArray.OBJECT;
 71         } else {
 72             mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity);
 73             mKeys = new int[mValues.length];
 74         }
 75         mSize = 0;
 76     }
 77     @Override
 78     @SuppressWarnings("unchecked")
 79     public SparseArray<E> clone() {
 80         SparseArray<E> clone = null;
 81         try {
 82             clone = (SparseArray<E>) super.clone();
 83             clone.mKeys = mKeys.clone();
 84             clone.mValues = mValues.clone();
 85         } catch (CloneNotSupportedException cnse) {
 86             /* ignore */
 87         }
 88         return clone;
 89     }
 90     /**
 91      * Gets the Object mapped from the specified key, or <code>null</code>
 92      * if no such mapping has been made.
 93      */
 94     public E get(int key) {
 95         return get(key, null);
 96     }
 97     /**
 98      * Gets the Object mapped from the specified key, or the specified Object
 99      * if no such mapping has been made.
100      */
101     @SuppressWarnings("unchecked")
102     public E get(int key, E valueIfKeyNotFound) {
103         int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
104         if (i < 0 || mValues[i] == DELETED) {
105             return valueIfKeyNotFound;
106         } else {
107             return (E) mValues[i];
108         }
109     }
110     /**
111      * Removes the mapping from the specified key, if there was any.
112      */
113     public void delete(int key) {
114         int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
115         if (i >= 0) {
116             if (mValues[i] != DELETED) {
117                 mValues[i] = DELETED;
118                 mGarbage = true;
119             }
120         }
121     }
122     /**
123      * @hide
124      * Removes the mapping from the specified key, if there was any, returning the old value.
125      */
126     public E removeReturnOld(int key) {
127         int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
128         if (i >= 0) {
129             if (mValues[i] != DELETED) {
130                 final E old = (E) mValues[i];
131                 mValues[i] = DELETED;
132                 mGarbage = true;
133                 return old;
134             }
135         }
136         return null;
137     }
138     /**
139      * Alias for {@link #delete(int)}.
140      */
141     public void remove(int key) {
142         delete(key);
143     }
144     /**
145      * Removes the mapping at the specified index.
146      */
147     public void removeAt(int index) {
148         if (mValues[index] != DELETED) {
149             mValues[index] = DELETED;
150             mGarbage = true;
151         }
152     }
153     /**
154      * Remove a range of mappings as a batch.
155      *
156      * @param index Index to begin at
157      * @param size Number of mappings to remove
158      */
159     public void removeAtRange(int index, int size) {
160         final int end = Math.min(mSize, index + size);
161         for (int i = index; i < end; i++) {
162             removeAt(i);
163         }
164     }
165     private void gc() {
166         // Log.e("SparseArray", "gc start with " + mSize);
167         int n = mSize;
168         int o = 0;
169         int[] keys = mKeys;
170         Object[] values = mValues;
171         for (int i = 0; i < n; i++) {
172             Object val = values[i];
173             if (val != DELETED) {
174                 if (i != o) {
175                     keys[o] = keys[i];
176                     values[o] = val;
177                     values[i] = null;
178                 }
179                 o++;
180             }
181         }
182         mGarbage = false;
183         mSize = o;
184         // Log.e("SparseArray", "gc end with " + mSize);
185     }
186     /**
187      * Adds a mapping from the specified key to the specified value,
188      * replacing the previous mapping from the specified key if there
189      * was one.
190      */
191     public void put(int key, E value) {
192         int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
193         if (i >= 0) {
194             mValues[i] = value;
195         } else {
196             i = ~i;
197             if (i < mSize && mValues[i] == DELETED) {
198                 mKeys[i] = key;
199                 mValues[i] = value;
200                 return;
201             }
202             if (mGarbage && mSize >= mKeys.length) {
203                 gc();
204                 // Search again because indices may have changed.
205                 i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
206             }
207             mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
208             mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
209             mSize++;
210         }
211     }
212     /**
213      * Returns the number of key-value mappings that this SparseArray
214      * currently stores.
215      */
216     public int size() {
217         if (mGarbage) {
218             gc();
219         }
220         return mSize;
221     }
222     /**
223      * Given an index in the range <code>0...size()-1</code>, returns
224      * the key from the <code>index</code>th key-value mapping that this
225      * SparseArray stores.
226      *
227      * <p>The keys corresponding to indices in ascending order are guaranteed to
228      * be in ascending order, e.g., <code>keyAt(0)</code> will return the
229      * smallest key and <code>keyAt(size()-1)</code> will return the largest
230      * key.</p>
231      */
232     public int keyAt(int index) {
233         if (mGarbage) {
234             gc();
235         }
236         return mKeys[index];
237     }
238     /**
239      * Given an index in the range <code>0...size()-1</code>, returns
240      * the value from the <code>index</code>th key-value mapping that this
241      * SparseArray stores.
242      *
243      * <p>The values corresponding to indices in ascending order are guaranteed
244      * to be associated with keys in ascending order, e.g.,
245      * <code>valueAt(0)</code> will return the value associated with the
246      * smallest key and <code>valueAt(size()-1)</code> will return the value
247      * associated with the largest key.</p>
248      */
249     @SuppressWarnings("unchecked")
250     public E valueAt(int index) {
251         if (mGarbage) {
252             gc();
253         }
254         return (E) mValues[index];
255     }
256     /**
257      * Given an index in the range <code>0...size()-1</code>, sets a new
258      * value for the <code>index</code>th key-value mapping that this
259      * SparseArray stores.
260      */
261     public void setValueAt(int index, E value) {
262         if (mGarbage) {
263             gc();
264         }
265         mValues[index] = value;
266     }
267     /**
268      * Returns the index for which {@link #keyAt} would return the
269      * specified key, or a negative number if the specified
270      * key is not mapped.
271      */
272     public int indexOfKey(int key) {
273         if (mGarbage) {
274             gc();
275         }
276         return ContainerHelpers.binarySearch(mKeys, mSize, key);
277     }
278     /**
279      * Returns an index for which {@link #valueAt} would return the
280      * specified key, or a negative number if no keys map to the
281      * specified value.
282      * <p>Beware that this is a linear search, unlike lookups by key,
283      * and that multiple keys can map to the same value and this will
284      * find only one of them.
285      * <p>Note also that unlike most collections' {@code indexOf} methods,
286      * this method compares values using {@code ==} rather than {@code equals}.
287      */
288     public int indexOfValue(E value) {
289         if (mGarbage) {
290             gc();
291         }
292         for (int i = 0; i < mSize; i++)
293             if (mValues[i] == value)
294                 return i;
295         return -1;
296     }
297     /**
298      * Removes all key-value mappings from this SparseArray.
299      */
300     public void clear() {
301         int n = mSize;
302         Object[] values = mValues;
303         for (int i = 0; i < n; i++) {
304             values[i] = null;
305         }
306         mSize = 0;
307         mGarbage = false;
308     }
309     /**
310      * Puts a key/value pair into the array, optimizing for the case where
311      * the key is greater than all existing keys in the array.
312      */
313     public void append(int key, E value) {
314         if (mSize != 0 && key <= mKeys[mSize - 1]) {
315             put(key, value);
316             return;
317         }
318         if (mGarbage && mSize >= mKeys.length) {
319             gc();
320         }
321         mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
322         mValues = GrowingArrayUtils.append(mValues, mSize, value);
323         mSize++;
324     }
325     /**
326      * {@inheritDoc}
327      *
328      * <p>This implementation composes a string by iterating over its mappings. If
329      * this map contains itself as a value, the string "(this Map)"
330      * will appear in its place.
331      */
332     @Override
333     public String toString() {
334         if (size() <= 0) {
335             return "{}";
336         }
337         StringBuilder buffer = new StringBuilder(mSize * 28);
338         buffer.append('{');
339         for (int i=0; i<mSize; i++) {
340             if (i > 0) {
341                 buffer.append(", ");
342             }
343             int key = keyAt(i);
344             buffer.append(key);
345             buffer.append('=');
346             Object value = valueAt(i);
347             if (value != this) {
348                 buffer.append(value);
349             } else {
350                 buffer.append("(this Map)");
351             }
352         }
353         buffer.append('}');
354         return buffer.toString();
355     }
356 }
SparseArray

相关文章:

  • 2022-12-23
  • 2021-09-14
  • 2022-02-07
  • 2021-04-08
  • 2022-12-23
  • 2021-09-08
猜你喜欢
  • 2022-03-02
  • 2022-12-23
  • 2018-06-20
  • 2021-07-10
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案