浅析Java集合类源码(一)--- Vector, ArrayList, LinkedList
2016-09-15 12:26
495 查看
1. Vector
Vector类继承 AbstractList ,实现了 List,RandomAccess,Cloneable,Serializable等接口,并且Vector大多数方法都有synchronized关键字,说明Vector是线程安全类。public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
(1)初始化
Vector 类初始化时需设置初始容量(initialCapacity)和容量增长率(capacityIncrement),默认初始容量为10,容量增长率为0public Vector(int initialCapacity, int capacityIncrement) public Vector(int initialCapacity) { this(initialCapacity, 0); } public Vector() { this(10); }
(2)查找
Vector采用数组来对对象进行存储protected Object[] elementData;
因此,可通过下标来查找对象,例如 : get(),set(),firstElement(),lastElement(),setElementAt(),insertElementAt()等方法的时间复杂度是O(1)
public synchronized E get(int index) public synchronized E set(int index, E element) public synchronized E firstElement() public synchronized E lastElement() public synchronized void setElementAt(E obj, int index) public synchronized voidinsertElementAt(E obj, int index)
(3)添加
当调用add()添加元素时,需要调用ensureCapacityHelper ()确保当前数组元素数量小于数组长度,否则调用grow()增长数组ensureCapacityHelper(elementCount + 1); if (minCapacity - elementData.length > 0) grow(minCapacity);
grow()方法,当设置了capacityIncrement时,原数组增长为(oldCapacity + capacityIncrement),否则增长为原数组的2倍((oldCapacity + oldCapacity))
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
然后将原数组内容复制到新容量的数组中,新数组增长容量的值设置为null
elementData = Arrays.copyOf(elementData, newCapacity);
因此,添加数组元素时,时间复杂度可能是O(1),也可能是O(n)
(4)删除
当需要移除某个对象时,使用removeElementAt(intindex) 方法。此时,removeElementAt方法会将数组的后半部分((index+1) ~ elementCount)的所有元素复制到index ~ (elementCount-1) 的位置,再将elementCount 置为null,以帮助GC(垃圾回收器)回收内存。平均时间复杂度是O(n)int j = elementCount - index - 1; if (j > 0) { System.arraycopy(elementData, index + 1, elementData, index, j); } elementCount--; elementData[elementCount] = null; /* to let gc do its work */
当使用remove(Object) 方法删除元素时,需要调用indexOf(Object) 方法扫描整个数组,时间复杂度是O(n)
2. ArrayList
ArrayList类继承 AbstractList ,实现了 List,RandomAccess,Cloneable,Serializable等接口,ArrayList是非线程安全类。public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
(1)初始化
ArrayList初始化时需要初始容量,默认为10,但并不是直接生成一个长度为10的数组,而是赋值一个空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA,再在ensureCapacity中判断元素数组是EMPTY_ELEMENTDATA还是DEFAULTCAPACITY_EMPTY_ELEMENTDATA。若是DEFAULTCAPACITY_EMPTY_ELEMENTDATA 再生成长度为10的数组。
private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } public void ensureCapacity(int minCapacity) { int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY; }
(2)查找
通过get(int index) 方法可查找特定下标的元素,此方法直接从elementData[] 数组中取元素,时间复杂度是O(1)public E get(int index) { rangeCheck(index); return elementData(index); } E elementData(int index) { return (E) elementData[index]; }
(3)添加
通过add() 方法可往数组中添加元素,需要调用ensureCapacityInternal保证数组的长度,再调用ensureExplicitCapacity,当需要时调用grow方法来扩展数组长度。ensureCapacityInternal(size + 1); ensureExplicitCapacity(minCapacity); if (minCapacity - elementData.length > 0) grow(minCapacity);
grow() 方法,扩展原有数组,扩展后的数组长度为原来数组的1.5倍。但是当数组需要的最小容量大于原数组的1.5倍是,则扩展为需要的最小容量。增加的数组元素是null。
int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; elementData = Arrays.copyOf(elementData, newCapacity);
在添加时,最好时间复杂度是O(1),最坏时间复杂度是O(n)(需要复制数组),平均时间复杂度是O(n)
(4)删除
通过remove(index) 方法删除元素时,此时,remove方法会将数组的后半部分((index+1) ~ size)的所有元素复制到index ~ (elementCount-1) 的位置,再将size置为null,以帮助GC(垃圾回收器)回收内存,平均时间复杂度O(n)。int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work
通过remove(Object o)对某个对象进行移除时,需要对整个数组进行扫描,获取此对象第一次出现的位置index,再调用fastRemove来移除此对象。fastRemove方法和remove(int index)方法类似,也是将数组的后半部分((index+1) ~ size)的所有元素复制到index ~ (elementCount-1) 的位置,再将size置为null,以帮助GC(垃圾回收器)回收内存。扫描数组和复制数组的平均时间复杂度均是O(n)。
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work
}
3. LinkedList
LinkedList类继承 AbstractSequentialList ,实现了 List,Deque,Cloneable,Serializable等接口, LinkedList是非线程安全类。LinkedList的基本数据结构是双向链表。public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
(1)初始化
LinkedList初始化并没有构造实质的列表。public LinkedList() { }
(2)查找
通过get(int index) 方法查找某个下标的元素,get() 方法调用node(int index)方法查找元素。public E get(int index) { checkElementIndex(index); return node(index).item; }
node(int index)方法先判断index位于链表的前半部分还是后半部分。若是位于前半部分,则从第一个元素开始向后遍历;若是位于前半部分,则从最后一个元素开始向前遍历。平均时间复杂度是 O(n/4)。
Node<E> node(int index) { if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } }
其他查找方法,如:getFirst(),getLast()的时间复杂度是O(1)
(3)添加
使用add() 方法添加元素时,会使用linkLast() 将元素添加到数组的末尾,时间复杂度是O(1)final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode;
(4)删除
当通过remove(int index) 方法移除指定下标元素时,其调用unlink方法断开连接public E remove(int index) { checkElementIndex(index); return unlink(node(index)); }
因为LinkedList是双向链表结构,unlink方法首先会断开删除元素element与前一个元素的相互连接,再断开删除元素element与后一个元素的相互连接。
final E element = x.item; final Node<E> next = x.next; final Node<E> 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;
由于调用remove方法时需要查找index的位置,因此平均时间复杂度是O(n/2)
相关文章推荐
- 源码浅析 ArrayList、Vector、LinkedList 的区别
- List接口实现类-ArrayList、Vector、LinkedList集合深入学习以及源码解析
- java中List接口的实现类 ArrayList,LinkedList,Vector 的区别 list实现类源码分析
- ArrayList和LinkedList和Vector源码分析
- java集合类,List和Set比较,各自的子类比较(ArrayList,Vector,LinkedList;HashSet,TreeSet),Map集合比较
- Java集合源码学习笔记(五)ArrayList,LinkedList,Vector和Hashtable,HashMap的比较
- Java集合类ArrayList、LinkedList、vector、SynchronizedList详解
- java中List接口的实现类 ArrayList,LinkedList,Vector 的区别 list实现类源码分析
- 浅析Java中的集合包(ArrayList,LinkedList,Vector, Stack,HashSet,TreeSet,HashMap,TreeMap)
- 搞懂JAVA集合类--List的实现 ArrayList、Vector、LinkedList(二)
- ArrayList LinkedList Vector类
- Array / ArrayList / Vector / LinkedList / Hashmap
- LinkedList,ArrayList,Vector,HashTable,HashMap
- ArrayList Vector LinkedList 各种容器的区别与用法
- ArrayList,LinkedList,Vector的区别
- ArrayList Vector LinkedList 区别与用法
- 【转】ArrayList Vector LinkedList 区别与用法
- ArrayList Vector LinkedList 区别与用法
- ArrayList Vector LinkedList 区别与用法
- Java优化编程--核心类与性能 Vector ArrayList LinkedList String