java.util包提供了两种java
ArrayList LinkedList
ArrayList比LinkedList经常使用不少,缘由是:
ArrayList查找更容易算法
ArrayList封装了一个数组Object[]数组
数组的初始化缓存
ArrayList array = new ArrayList();
封装一个空数组, {}安全
ArrayList array = new ArrayList(10);
封装一个大小为10的数组 new Object[10];
性能优化
数组如何实现扩容
数据结构
ArrayList.add/addAll都须要先进行扩容检查,
相似,并发
对象调用方法,要进行对象判空, UI操做以前要进行,线程检查
扩容检查: size+增长的大小 与 数组.length 比较
计算数组扩容的数组长度:性能
首先,扩容至原数组大小的一倍,size+增长的大 小与其比较:
若是大于,扩容至原数组大小的一倍
若是小于,扩容至size+增长的大小;优化
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
扩容使用的是: Array.copyof(array, newLen)
removeAll如何实现
与remove()不一样,remove使用System.copy完成数组的 部分移动
而removeAll,使用的算法:
ArrayList array1 = new ArrayList(); array1.addAll({0,3,5,7,3,6}); int[] array2 = {3,5,4}; array1.removeAll(array2);
首先,遍历array1中每一个元素,若元素 不在array2内,将计数位置的值设置为元素的值并将计 数+1;
遍历完成后,计数为数组剩余元素的个 数,将计数以后的元素清空.
算法详细:
  0,3,5,7,3,6 ;<br>   遍历以后,计数为2,数组为0,7,6,7,3,6;<br>   清空以后,0,7,6,null,null,null;
Node的数据结构
Node<E> { E element; Node<E> prev; Node<E> next; }
基本结构
Node<E> first, last
Linked是双向链表,first,last指向表头,表尾
java.util包提供了两种Map:
1.HashMap
2.TreeMap
Android为了性能优化,提供了HashMap的替代品:
1.ArrayMap
2.SparseMap
它俩能够在数据量都在千级之内的状况下,
若是key的类型为int,使用SparseMap,
若是key的类型为其它类型,使用ArrayMap
HashMap相比TreeMap更经常使用
数据结构
Node的数据结构:
Node<K,V> { int hash; K key; V value; Node<K,V> next; }
基本数据结构:
Node<K,V>[] table; float loadFoctor;//默认值0.75f int threshold;
能够看出HashMap的数据结构是数组+链表
扩容
何时扩容
当调用put/putAll时,实际上都是调用putVal方法
先建立Node,再查看新的Node放入数组,仍是链表;
当++size>threshold,则须要扩容
table如何扩容
它的扩容包含两个步骤:
1. 肯定扩容的大小; 2. 如何移动元素,包含数组中的元素与链表中的元素;<br>
肯定扩容的大小:
threshold默认值 = 16*0.75f=12
每次扩容,
先建立一个threadhold大小的数组,赋给tble,也就是扩容至threadhold
再,threadhold = threadhold <<1,扩大一倍
如何移动元素,包含数组中的元素与链表中的元素:
1.若是元素只在数组里,而没有链表:
新的位置是 e.hash&(newCap-1)
2.元素在链表上:
根据(e.hash & oldCap) == 0 决定是在原位置仍是在原位置+oldCap上
链表可能会分为两部分
数据结构
TreeMapEntry的数据结构
TreeMapEntry<K, V> { K key; V value; TreeMapEntry<K, V> left; TreeMapEntry<K, V> right; TreeMapEntry<K, V> parent; }
TreeMap的数据结构:
TreeMapEntry<K, V> root; Comparator<? super K> comparator;
数据结构
int[] mKeys; Object[] mValues;
Vector
HashTable
用于读写分离,实现读并发,写同步
并发的不一样策略:
1.Blocking容器
2.CopyOnWrite容器
3.Concurrent容器
用于解决限制容量的容器的存取问题
相似生产者-消费者
容器为空时,阻塞取线程
容器满时,阻塞存线程
写时赋值,即添加元素时,先复制整个容器,添加到复制的容器中,
再将容器引用指向复制的容器,达到读的最大并发;
适用于读多写少的状况;
使用分段锁,首先将容器分红多段,每段使用不一样的锁,对不一样段达到读写并发,相同段读并发,写同步