List概述
List属于Java集合系统一员。List本身是一个interface继承了Collection接口。List中定义各种对集合的操作,List的具体实现包括ArrayList、Vector和LinkedList等,List所处位置如下图所示(非完整图):
![28e8ce0b8a71e05aa3562c2b4ec1a3de.png](https://i-blog.csdnimg.cn/blog_migrate/43ce5ca6d13d33647bffba8e6e6d2993.jpeg)
List提供了特殊迭代器ListIterator,该迭代器提供了双向迭代访问集合的功能。 接口方法如下所示:
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
List具体实现类
List实现类主要包括ArrayList、Vector和LinkedList。
ArrayList
ArrayList类关系图如下所示:
![28289c8a20ba679f8b83137e818ee7a4.png](https://i-blog.csdnimg.cn/blog_migrate/bdc791ebb60a3d9cf045035ea7bdeaa7.jpeg)
注意:
其中RandomAccess接口只是个标记表面该接口的具体实现可以支持随机访问,RandomAccess本身不定义任何东西;
Cloneable接口作为支持field-for-field拷贝标记,如果实现该接口,会报”CloneNotSupportedException”错误;
Serializable序列号接口标记;serialVersionUID建议显示指定,因为不同的java编译器自动生成serialVersionUID的时候可能不一样,会报”InvalidClassException”错误
ArrayList底层数据结构为数组,因此支持随机访问
Object[] elementData
contain方法是通过遍历实现,因此时间复杂度线性的
扩容机制
ArrayList的扩容机制相对来说比较简单,如下所示:
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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);
}
通常情况下一次扩容后大小为原来的三倍。
fail-fast
fail-fast是Java集合的一种错误检测机制。在用迭代器对List进行遍历的时候,如果有其它线程对List进行了结构性修改,则会报: ConcurrentModificationException。
不要在foreach中对元素进行remove/add操作。如果需要remove元素请用iterator方式,并发操作的时候需要加锁。
modCount
记录对list进行结构化修改的次数,所谓结构化修改(Structurally modified)即改变list大小的操作
removeAll()
删除指定的集合元素
方法定义:
public boolean removeAll(Collection<?> c)
底层调用batchRemove方法,batchRemove方法基本思想就是会一边遍历List一边把不在指定集合中的原始往前挪,源代码如下所示:
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
获取子串subList
由源码可知获取子串是由定义的SubList类实现,其实获取并未重新开辟空间,引用的还是原始的数据;
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
Spliterator可拆分迭代器
Spliterator用于遍历和对源数据进行分区,源数据可以是数组,集合,IO通道或者是生成函数;Spliterator可以单独遍历元素(tryAdvance)或者批量遍历元素(forEachRemaining)
主要方法
1) trySplit
并行操作时,可以通过trySplit方法将spliterator划分为另外一个spliterator
2) characteristics
包括spliterator特性,特性包括:DISTINCT, SORTED,SIZED,NOTNULL, IMMUTABLE,CONCURRENT,SUBSIZED
该特性被定义为4个字节的int类型,如:
public static final int DISTINCT = 0x00000001;
public static final int SORTED = 0x00000004;
public static final int SIZED = 0x00000040;
具体使用时候通过按位与判断数据所具有的特性,如ArrayListSpliterator中该方法定义如下:
public int characteristics() {
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
3)estimateSize
评估剩余访问元素的大小
ArrayListSpliterator
略
非线程安全
ArrayList本身是非线程安全的。
Vector
Vector和ArrayList实现类似,底层数据结构也是数组,Vector是线程安全的而ArrayList是非线程安全的;Vector方法由synchronized修饰,从而保证线程安全;
扩容策略
当变量capacityIncrement <= 0时候 扩容为原先数组大小的两倍,否则扩容capacityIncrement
LinkedList
LinkedList双端链表,实现了List和deque接口,非线程安全,如果要支持线程安全,需要从外部进行保证,如可以通过Collections.sychronizedList进行封装,如下所示:
List list = Collections.synchronizedList(new LinkedList());
linkedList在集合系统中所处位置如下所示:
![5112956ce98c9b77152dd603457d928b.png](https://i-blog.csdnimg.cn/blog_migrate/840a7d951b165ed89eeafd63ea7bdc29.jpeg)
ListIterator迭代器
ListIterator继承Iterator实现了List的迭代访问,ListIterator主要定义了hasNext(), next(), hasPrevious(), previous()等一系列方法,LinkedList定义内部累ListItr改类实现ListIterator接口,通过ListItr达到链表双向访问的目的
toArray方法
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;
Object[] result = a;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
if (a.length > size)
a[size] = null;
return a;
}
其它
Arrays.copyOf
Arrays.copyOf(T[] original, int newLength) 在调用的时候会创建新的数组,底层实际上是通过调用System.arraycopy实现的
Arrays.sort
底层为归并排序