List源码解析
开始看一下集合Collection,List是Collection的一个子接口,主要是看一下其下的几个类。
1、AbstractList
2、ArrayList
3、Collections.synchronizedList
4、Vector
5、LinkedList
6、CopyOnWriteArrayList
一、AbstractList
这是一个抽象类,其是实现List接口基础类,像ArrayList、LinkedList和Vector都是继承此抽象类的。
1》如果要实现一个不可变的列表,必须实现get(int) 和size()方法
2》如果要实现一个可修改的列表,必须实现set(int,E),如果列表大小可变,必须另外实现add(int,E)和remove(int)方法
其内置了两个迭代器,是Itr和ListItr,继承关系如下
(1)Itr
private class Itr implements Iterator<E> { //游标 int cursor = 0; //调用next方法时当前的下标索引值 //,如果调用了remove方法,则重置为-1 int lastRet = -1; //列表被修改的次数,比如增、删、改、扩容等操作 int expectedModCount = modCount; //是否还有元素 public boolean hasNext() { return cursor != size(); } //返回下一个元素 public E next() { checkForComodification(); try { int i = cursor; //get方法是调用具体实现类的 E next = get(i); lastRet = i; cursor = i + 1; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } //删除当前元素 public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this.remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } } //检查迭代的时候列表结构是否有被其他线程修改过 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
(2)ListItr
private class ListItr extends Itr implements ListIterator<E> { ListItr(int index) { cursor = index; } public boolean hasPrevious() { return cursor != 0; } //返回前一个元素 public E previous() { checkForComodification(); try { int i = cursor - 1; E previous = get(i); lastRet = cursor = i; return previous; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } public int nextIndex() { return cursor; } public int previousIndex() { return cursor-1; } //设值 public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this.set(lastRet, e); expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } //添加元素 public void add(E e) { checkForComodification(); try { int i = cursor; AbstractList.this.add(i, e); lastRet = -1; cursor = i + 1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } }
这两个迭代器在indexOf、lastIndexOf和removeRange方法中有调用
例如removeRange方法
protected void removeRange(int fromIndex, int toIndex) { //获取迭代器,fromIndex就是Itr里面的cursor ListIterator<E> it = listIterator(fromIndex); for (int i=0, n=toIndex-fromIndex; i<n; i++) { it.next(); it.remove(); } } public ListIterator<E> listIterator(final int index) { rangeCheckForAdd(index); return new ListItr(index); } private class ListItr extends Itr implements ListIterator<E> { ListItr(int index) { cursor = index; } }
二、ArrayList
这个列表是最常用的,继承自AbstractList,非线程安全,多线程下会抛出ConcurrentModificationException
(1)默认容量是10
private static final int DEFAULT_CAPACITY = 10;
(2)底层数据结构是一个Object数组
transient Object[] elementData;
(3)扩容机制为扩容为当前容量的1.5倍,看add方法
public boolean add(E e) { //关键就是方法 ensureCapacityInternal(size + 1); elementData[size++] = e; return true; }
扩容看ensureCapacityInternal方法
private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity( calculateCapacity(elementData, minCapacity) ); }
先看calculateCapacity方法
private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }
如果创建列表时没有指定大小,就从minCapacity和默认容量两个数中取最大。否则直接返回minCapacity
private void ensureExplicitCapacity(int minCapacity) { modCount++; //如果minCapacity大于当前数组长度,则进行扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); }
扩容最核心的方法是grow(minCapacity)方法。
private void grow(int minCapacity) { //当前容量 int oldCapacity = elementData.length; //新容量,是当前容量的1.5倍 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); }
可以看到,扩容后容量为当前容量的1.5倍
三、Collections.synchronizedList
用Collections获取的这个List是线程安全的,其都是用synchronized关键字在代码块上进行加锁的。具体初始容量以及扩容看传入的是哪种List
返回的list是SynchronizedRandomAccessList或者是SynchronizedList,而SynchronizedRandomAccessList又是SynchronizedList的子类
所以主要看SynchronizedList,可以看到,这个类的所有方法都是用Synchronized加锁的。
四、Vector
Vector比较少用,其也是AbstractList的子类。
(1)默认容量,也是10
public Vector() { //调用另外一个构造方法 this(10); }
上述默认空构造调用下面这个构造方法,其将capacityIncrement设为0,这个在扩容时有用
也可以用下面这个构造初始化容量和capacityIncrement
(2)底层数据结构是一个Object数组
protected Object[] elementData;
(3)扩容机制默认是2倍,也可以手动设置capacityIncrement扩容
(4)线程安全,用Synchronized在方法上加锁
五、LinkedList
这个链表结构如下,除了继承了AbstractList,还实现了Queue。
(1)底层实现是一个一个Node节点,节点中存有前后节点的引用,能连成一条链
六、CopyOnWriteArrayList
这个就比较牛逼了,中文名叫写时复制。属于JUC并发包里面的,线程安全,是ArrayList的变体。
(1)初始化是容量为0的Object数组
public CopyOnWriteArrayList() { setArray(new Object[0]); }
这个数组是用volatile,保证变量内存可见性。
private transient volatile Object[] array;
(2)用ReentrantLock(递归锁,又称可重入锁)加锁,扩容为添加一次就容量加1,然后用Arrays.copyOf将旧的数组复制到新数组内,比较耗内存。
=======================================================
我是Liusy,一个喜欢健身的程序员。
欢迎关注微信公众号【Liusy01】,一起交流Java技术及健身,获取更多干货。