一、类继承关系
二、接口功能概述
List接口表示一个有序的集合,也称为列表,调用方可以控制元素插入列表的位置,可以根据元素在列表中的位置随机访问某个元素,也可以搜索指定元素。List接口提供了一个特殊的迭代器ListIterator,该迭代器扩展自Iterator,增加了倒序遍历,添加元素,修改元素的方法。两者包含的方法如下:
参考用例如下:
@Test
public void test() throws Exception {
List<String> test=new ArrayList<>();
test.add("test");
test.add("test2");
test.add("test4");
test.add("test3");
test.add("test2");
test.add("test6");
test.add("test5");
System.out.println("test2 index:"+test.indexOf("test2"));
System.out.println("test2 lastIndex:"+test.lastIndexOf("test2"));
List<String> sub=test.subList(2,5 );
System.out.println("=========subList=========");
for(String str:sub){
System.out.println(str);
}
test.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
System.out.println("=========sort=========");
for(String str:test){
System.out.println(str);
}
}
@Test
public void test2() throws Exception {
List<String> test=new ArrayList<>();
test.add("test");
test.add("test2");
test.add("test4");
test.add("test3");
test.add("test2");
test.add("test6");
test.add("test5");
// ListIterator<String> listIterator=test.listIterator();
//在指定索引处开始遍历
ListIterator<String> listIterator=test.listIterator(1);
while (listIterator.hasNext()){
String str=listIterator.next();
System.out.println("next:"+str);
if(str.equals("test")){
listIterator.set("testa");
}
if(str.equals("test3")){
listIterator.add("testb");
}
if(str.equals("test6")){
listIterator.remove();
}
}
while (listIterator.hasPrevious()){
String str=listIterator.previous();
System.out.println("previous:"+str);
}
}
RandomAccess接口是一个标记类接口,表明当前实现类支持以常量级的时间随机访问列表元素,调用方可以根据目标类是否实现了RandomAccess接口来决定是否使用该类随机访问列表元素,参考如下用例:
@Test
public void test3() throws Exception {
List<String> list=new ArrayList<>();
list.add("test");
List<String> list2=new LinkedList<>();
list.add("test2");
System.out.println(get(list, 0));
System.out.println(get(list2, 0));
}
private <T> T get(List<T> list, int index){
if(list instanceof RandomAccess){
return list.get(index);
}else{
throw new UnsupportedOperationException();
}
}
三、接口实现
1、ArrayList
ArrayList是基于数组实现的List接口,允许元素为空,可以自动调整数组容量,非线程安全,遍历时修改会快速失败。ArrayList扩容的核心操作是将原数组中的内容复制到扩容后的新数组中,执行该操作的方法是System.arraycopy()方法,是一个本地方法,性能较高,但是为了避免多次扩容多次分配数组内存,当ArrayList中的元素个数预计较多时应该提前调用ensureCapacity()确保一次分配足够大的数组。
1.1、全局变量
/**
* 默认初始容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 共享的空数组实例
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 共享的默认容量的空数组
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 保存元素的数组
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 元素个数
*/
private int size;
/**
*最大数组容量
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
1.2 构造方法
//构建指定容量的列表
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 ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// 部分情形c.toArray()返回的不是Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
1.3 数组扩容
//计算最低容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
/**
*确保数组至少能容纳minCapacity个元素,必要时扩容
*/
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//扩容长度大于当前数组长度则扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//扩容数组
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//默认扩容50%
int newCapacity = oldCapacity + (oldCapacity >> 1);
//扩容50%后低于minCapacity以minCapacity为准
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果大于MAX_ARRAY_SIZE
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 将当前数组复制到一个扩容的数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
1.4 元素添加
public boolean add(E e) {
ensureCapacityInternal(size + 1); //自增modCount,必要时扩容
//此处自增size
elementData[size++] = e;
return true;
}
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); //自增modCount,必要时扩容
System.arraycopy(elementData, index, elementData, index + 1,
size - index);//将elementData中index以后的元素往后挪一位
elementData[index] = element;
size++;
}
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); //自增modCount,必要时扩容
System.arraycopy(a, 0, elementData, size, numNew);//将新数组a中的元素复制到elementData的size索引处
size += numNew;
return numNew != 0;
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
//执行扩容
ensureCapacityInternal(size + numNew); // Increments modCount
//表示原数组中需要移动的元素个数
int numMoved = size - index;
if (numMoved > 0)
//将原数组中需要移动的元素往后移动numNew位
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
//将目标数组c中的元素复制到源数组中
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
1.5 元素修改
public E get(int index) {
//检查索引范围
rangeCheck(index);
return elementData(index);
}
//元素查找都是遍历数组完成的,顺序查找
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
//null用==来比较
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
//非空元素用equals()方法
if (o.equals(elementData[i]))
return i;
}
return -1;
}
/**
* 倒序遍历数组,查找元素
*/
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
1.6、元素修改
/**
* 给定索引的元素设置新值,注意修改指定索引的元素时修改次数未增加
*/
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
1.7 元素删除
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);
elementData[--size] = null; // 最后一个数组位置为null,便于垃圾回收和数组修剪
return oldValue;
}
/**
* 先查找目标元素索引再执行删除
*/
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
//同remove逻辑,少了index的校验逻辑
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
}
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
//批量移除操作避免频繁复制数组
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 {
// 如果contains()方法抛出异常,循环终止
if (r != size) {
//将索引为r后面的元素复制到w后面
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
//w==size表示原数组未发生修改
if (w != size) {
//将w以后的数组位置为null
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
//删除指定范围索引的元素
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
//需要移动的元素个数
int numMoved = size - toIndex;
//将toIndex后面的元素往前移动到fromIndex
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// 多余的数组位置null
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}
1.8 元素遍历
private class Itr implements Iterator<E> {
int cursor; // 当前元素在数组中索引
int lastRet = -1; // 上一个元素在数组中的索引
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
//元素移除后,后面的元素会补充到被删除元素的数组位上,所以下一个遍历元素的索引还是lastRet
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;//置为-1,避免重复调用
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
//还原上面跳出while循环时的i++
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor - 1;
}
@SuppressWarnings("unchecked")
public E previous() {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i;
return (E) elementData[lastRet = i];
}
public void set(E e) {
//ArrayList更改元素时modCount没有变,所以此处不需要重置expectedModCount
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.set(lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
//cusor加1,跳过添加的这个元素,保证本次遍历不受影响
cursor = i + 1;
lastRet = -1;//置为-1,避免重复调用
expectedModCount = modCount; //重置expectedModCount
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
1.9 子列表
//SubList内部并未复制原数组指定范围的元素,而是继续操作原数组
private class SubList extends AbstractList<E> implements RandomAccess {
private final AbstractList<E> parent;
private final int parentOffset;
private final int offset;
int size;
SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
//父ArrayList的起始索引
this.parentOffset = fromIndex;
//这个是相对于原始的父ArrayList的起始索引,一级subList时,offset为0,parentOffset等于offset,对一级subList取二级subList两个就相差offset了
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
public E set(int index, E e) {
rangeCheck(index);
checkForComodification();
//将子List的index转换成原数组的index
//此处没有调用父ArrayList的get()方法,而是直接操作父ArrayList的内部数组,多级子List时查找元素更快
E oldValue = ArrayList.this.elementData(offset + index);
ArrayList.this.elementData[offset + index] = e;
return oldValue;
}
public E get(int index) {
rangeCheck(index);
checkForComodification();
//将子List的index转换成原数组的index
return ArrayList.this.elementData(offset + index);
}
public int size() {
checkForComodification();
return this.size;
}
public void add(int index, E e) {
rangeCheckForAdd(index);
checkForComodification();
//此处用父ArrayList的add方法而不是直接操作elementData是为了规避数组扩容和modCount增加的问题
parent.add(parentOffset + index, e);
this.modCount = parent.modCount;
this.size++;
}
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = parent.remove(parentOffset + index);
this.modCount = parent.modCount;
this.size--;
return result;
}
protected void removeRange(int fromIndex, int toIndex) {
checkForComodification();
parent.removeRange(parentOffset + fromIndex,
parentOffset + toIndex);
this.modCount = parent.modCount;
this.size -= toIndex - fromIndex;
}
public boolean addAll(Collection<? extends E> c) {
return addAll(this.size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
int cSize = c.size();
if (cSize==0)
return false;
checkForComodification();
parent.addAll(parentOffset + index, c);
this.modCount = parent.modCount;
this.size += cSize;
return true;
}
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator(final int index) {
checkForComodification();
rangeCheckForAdd(index);
final int offset = this.offset;
return new ListIterator<E>() {
int cursor = index;
int lastRet = -1;
int expectedModCount = ArrayList.this.modCount;
public boolean hasNext() {
return cursor != SubList.this.size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= SubList.this.size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[offset + (lastRet = i)];
}
public boolean hasPrevious() {
return cursor != 0;
}
@SuppressWarnings("unchecked")
public E previous() {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i;
return (E) elementData[offset + (lastRet = i)];
}
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = SubList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[offset + (i++)]);
}
// update once at end of iteration to reduce heap write traffic
lastRet = cursor = i;
checkForComodification();
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor - 1;
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
SubList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.set(offset + lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
SubList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (expectedModCount != ArrayList.this.modCount)
throw new ConcurrentModificationException();
}
};
}
1.10 toArray方法
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)//目标数组较小
//复制到一个新数组中
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);//目标数组够大,将原数组中元素复制到目标数组中
if (a.length > size)
a[size] = null;//size处置为null
return a;
}
2、Vector
Vector的实现跟ArrayList是几乎一致的,都是基于数组和数组复制,最大的区别在于Vector是线程安全的,所有可能导致数据不一致的方法都加了synchronized关键字。除此之外,Vector每次扩容的量是可以指定的,ArrayList是在原来的基础上先扩容50%,如果不符合最低容量要求则以最低容量为准。另外在非并发的环境下,官方推荐优先使用ArrayList。Vector相关代码如下:
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(int initialCapacity) {
this(initialCapacity, 0);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//每次扩容时增加的容量时capacityIncrement,如果该值为0则容量翻倍
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
//删除元素的逻辑同ArrayList,就是增加了synchronized关键字确保线程安全
public synchronized E remove(int index) {
modCount++;
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
int numMoved = elementCount - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--elementCount] = null; // Let gc do its work
return oldValue;
}
3、Stack
Stack仅仅只是扩展自Vector接口并未实现新的接口,只是增加了后进先出队列用到了几个方法而已,方法实现也非常简单。不推荐使用该类,而是采用Deque接口的实现类,如ArrayDeque。Stack新增的方法如下: