table = newTab;
可以看到当我们的table数组存储的节点值大于threshold时,会按我们的当前数组大小的两倍生成一个新的数组,并把旧数组上的数据复制到新数组上这就是我们的HashMap扩容。伴随着一个新数组的生成和数组数据的copy,会有一定性能上的损耗。如果我们在使用HashMap的是能够明确HashMap能够一开始就清楚的知道HashMap存储的键值对个数,我建议我们使用HashMap的另一个构造方法。
public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); }
注意了这个initialCapacity值最好去2的整数次幂。如果我们要存放40个键值对,那我们这个initialCapacity最好传64。至于为什么这样,我们下次在去讨论。
下面我们来分析HashMap的get方法:
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
在get的时候,我们首先会根据我们的key去计算它的hash值,如果这个hash值不存在,我们直接反回null。
如果存在,在没有发生hash冲突的情况下也就是根据当前hash值计算出的索引上的存储数据不是以树和链表的形式存储的时候,我们直接返回当前索引上存储的值,如果时链表树,我们就去遍历节点上的数据通过equals去比对,找到我们需要的在返回。
通过上面我可以得出结论,当HashMap没有发生hash冲突时,hashMap的查找和插入的时间复杂度都是O(1),效率时非常高的。
当我们发生扩容和hash冲突时,会带来一定性能上的损耗。
HashMap大致分析完了。
下面我们来分析分析Android为我们提供的ArrayMap和SparseArray。
二.我们在来看看ArrayMap:
public class A