源码分析(5)-ArrayList、Vector和LinkedList(JDK1.8)
一、概述
1、线程安全:ArrayList和LinkedList非线程安全的、Vector线程安全的,synchronized同步锁机制。
2、底层数据结构:ArrayList和Vector底层数据结构是数组;LinkedList双向链表。
3、时间复杂度是否受插入和删除元素位置影响:ArrayList和Vector受影响,add(E e)方法时间复杂度O(1)和add(int index, E element)方法时间复杂度O(n-index);LinkedList受影响,add(E e)方法时间复杂度O(1)和add(int index, E element)方法时间复杂度O(n)。
4、是否支持随机访问:ArrayList和Vector支持随机访问,因为实现了java.util.RandomAccess接口;LinkedList不支持。
5、内存空间占用:ArrayList和Vector空间浪费主要体现在在list列表的结尾会预留一定的容量空间;LinkedList空间花费则体现在每一个元素都需要消耗更多的空间(因为要存放前向元素和后向以及数据)。
6、是否支持克隆:ArrayList、Vector和LinkedList都实现java.lang.Cloneable接口,实现clone方法。
7、序列化:ArrayList、Vector和LinkedList都实现java.io.Serializable接口。
二、集合UML类图
ArrayList和Vector继承和实现相同,LinkedList实现java.util.Deque
三、ArrayList源码分析
1、构造方法
1 //无参构造方法 2 public ArrayList() { 3 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; 4 } 5 //指定初始容量的,构造方法 6 public ArrayList(int initialCapacity) { 7 if (initialCapacity > 0) { 8 this.elementData = new Object[initialCapacity]; 9 } else if (initialCapacity == 0) { 10 this.elementData = EMPTY_ELEMENTDATA;//指定为默认空数组 11 } else { 12 throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); 14 } 15 } 16 //指定初始集合对象,构造方法 17 public ArrayList(Collection<? extends E> c) { 18 elementData = c.toArray();//转化成数组 19 if ((size = elementData.length) != 0) { 20 // c.toArray might (incorrectly) not return Object[] (see 6260652) 21 if (elementData.getClass() != Object[].class) 22 elementData = Arrays.copyOf(elementData, size, Object[].class);//复制数组到 23 } else { 24 // replace with empty array. 25 this.elementData = EMPTY_ELEMENTDATA; 26 } 27 }
2、重要成员变量
//默认初始容量
private static final int DEFAULT_CAPACITY = 10;
//空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认容量10的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//数组,存储数据 transient Object[] elementData; //数组长度 private int size;
//最大的数组容量(长度)
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//数组结构变更次数
protected transient int modCount = 0; //该属性在父类java.util.AbstractList中
3、插入
//添加元素 public boolean add(E e) { ensureCapacityInternal(size + 1);//确认容量足够 elementData[size++] = e; return true; } // private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } //计算容量 private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity);//初始化容量10,比较初始容量与最小容量,返回两者之间最大的那个的值 } return minCapacity; } // 确保容量 private void ensureExplicitCapacity(int minCapacity) { modCount++;//数组结构性修改次数+1 // overflow-conscious code if (minCapacity - elementData.length > 0)//如果需要的最小容量大于当前数组长度,进行扩容 grow(minCapacity); } //扩容 private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1);扩容1.5倍 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);//复制数组 }
//指定位置添加数组 public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index);//复制插入数组 elementData[index] = element; size++; }
4、删除
//删除元素 public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved);数组复制,index位置以后的元素前移1个位置 elementData[--size] = null; // clear to let GC do its work return oldValue; }
扩展:
System.arraycopy()和Arrays.copyOf()方法:
//本地方法
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
1 //复制数组生成新的长度的数组 2 public staticT[] copyOf(T[] original, int newLength) { 3 return (T[]) copyOf(original, newLength, original.getClass()); 4 } 5 // 6 public static T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { 7 @SuppressWarnings("unchecked") 8 T[] copy = ((Object)newType == (Object)Object[].class) 9 ? (T[]) new Object[newLength] 10 : (T[]) Array.newInstance(newType.getComponentType(), newLength); 11 System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); 13 return copy; 14 }
1、arraycopy()需要目标数组,将原数组拷贝到你自己定义的数组里,而且可以选择拷贝的起点和长度以及放入新数组中的位置。
2、copyOf()是系统自动在内部新建一个数组,并返回该数组。
四、Vector源码分析
成员方法和ArrayList相似,不同之处在于方法都是synchronized同步锁修饰。
1、构造方法
//无参构造方法,初始容量10 public Vector() { this(10); } //指定初始容量构造方法 public Vector(int initialCapacity) { this(initialCapacity, 0); } //指定初始容量和容量增长,构造方法 public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; } //指定集合的构造方法 public Vector(Collection<? extends E> c) { elementData = c.toArray(); elementCount = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, elementCount, Object[].class); }
2、重要成员变量
//数组,存储数据和ArrayList相同 protected Object[] elementData; //数组长度,等同于ArrayList的size protected int elementCount; //扩容量 protected int capacityIncrement;
3、插入
//添加元素 public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1);//确保容量 elementData[elementCount++] = e;//尾部添加元素 return true; } // private void ensureCapacityHelper(int minCapacity) { // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity);//扩容 } // private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);//如果容量增长大于0,容量增加capacityIncrement;如果不大于0,扩容2倍 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity);//复制数组 }
五、LinkedList源码分析
LinkedList是一个实现了List接口和Deque接口的双端链表。 LinkedList底层的链表结构使它支持高效的插入和删除操作,另外它实现了Deque接口,使得LinkedList类也具有队列的特性; LinkedList不是线程安全的,如果想使LinkedList变成线程安全的,可以调用静态类Collections类中的synchronizedList方法:
List list=Collections.synchronizedList(new LinkedList(...));
1、构造方法
// public LinkedList() {} // public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
2、重要成员变量
//双向链表节点长度 transient int size = 0; //头结点 transient Nodefirst; //尾结点 transient Node last;
3、数据结构
private static class Node{ E item;//数据 Node next;//下一个节点 Node prev;//前一个节点 Node(Node prev, E element, Node next) { this.item = element; this.next = next; this.prev = prev; } }
4、插入
//插入到头部 public void addFirst(E e) { linkFirst(e); } // private void linkFirst(E e) { final Nodef = first;//头结点 final Node newNode = new Node<>(null, e, f); first = newNode; if (f == null)//头结点为空 last = newNode; else f.prev = newNode;//原头结点的前一个节点指向新节点 size++; modCount++; }
//尾部添加节点 public void addLast(E e) { linkLast(e); } // void linkLast(E e) { final Nodel = last;//尾结点 final Node newNode = new Node<>(l, e, null); last = newNode; if (l == null)//尾结点为空,此时头尾节点都是空 first = newNode; else l.next = newNode;//尾结点执行新节点 size++; modCount++; }
//插入节点默认在尾部添加 public boolean add(E e) { linkLast(e); return true; }
//指定位置添加节点 public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element);//尾部添加节点 else linkBefore(element, node(index)); } // void linkBefore(E e, Nodesucc) { // assert succ != null; final Node pred = succ.prev; final Node newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
// Nodenode(int index) { // assert isElementIndex(index); if (index < (size >> 1)) {//插入位置小于0.5*size,正向遍历 Node x = first; for (int i = 0; i < index; i++)//查询待插入位置节点 x = x.next; return x; } else { Node x = last; for (int i = size - 1; i > index; i--)//逆向遍历 x = x.prev; return x; } }
4、删除
//删除指定位置元素 public E remove(int index) { checkElementIndex(index); return unlink(node(index));//遍历查询index位置元素 } // E unlink(Nodex) {//删除数据 // assert x != null; final E element = x.item; final Node next = x.next; final Node prev = x.prev; if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; }
其他方法不再讲解。