接口List
public interface List<E> extends Collection<E> {}
List接口继承Collection接口,它提供一种索引概念,就像数组下标一样,让我们可以快速找到对应索引位置的元素,也可以在索引位置添加,删除,替换对应元素。
对比Collection接口,想一下List接口拥有的方法,肯定与索引有关系。
添加元素
// 继承自Collection接口方法
boolean add(E e);
boolean addAll(Collection<? extends E> c);
// List接口新加方法,在指定索引位置添加元素
void add(int index, E element);
boolean addAll(int index, Collection<? extends E> c);
删除元素
// 继承自Collection接口方法
boolean remove(Object o);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
// List接口新加方法,删除指定索引位置元素
E remove(int index);
替换元素
// List接口新加方法, 替换指定索引位置的元素
E set(int index, E element);
查询操作
// 继承自Collection接口方法
boolean contains(Object o);
boolean containsAll(Collection<?> c);
Iterator<E> iterator();
// List接口新加方法, 根据索引查找对应元素,根据元素查找索引位置
E get(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
// List接口新加方法, 返回功能性更强的迭代器ListIterator
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
其他重要方法
int size();
boolean isEmpty();
Object[] toArray();
<T> T[] toArray(T[] a);
// List接口新加方法,返回fromIndex位置到toIndex位置的子集合,
// (包括fromIndex,不包括toIndex)
List<E> subList(int fromIndex, int toIndex);
接口ListIterator
在List接口中,我们发现它返回了一个新的迭代器类型ListIterator。这个又是做什么用的呢?
我们知道Iterator接口有三个方法(forEachRemaining请忽略不计)。通过hasNext和next方法来遍历数组,通过remove方法来删除数组。
你会发现它没有添加和替换的方法,那是因为不同集合根据它数据结构的不同,添加和替换的操作不好界定,所以就交给它们各自独特的迭代器来实现,比如说这里的ListIterator。而最顶层的迭代器只提供这个三个方法。
我们知道List集合可以通过索引查找集合中的元素,所以List集合是一个连续的集合,可以查找前一个索引的元素,也可以查找后一个索引的元素,还可以添加替换元素。
public interface ListIterator<E> extends Iterator<E> {
// 继承自Iterator中的方法
boolean hasNext();
E next();
void remove();
// 反向遍历集合时使用
boolean hasPrevious();
E previous();
// 如果是正向遍历集合,nextIndex返回值表示集合中下一个元素的索引位置。
// 如果是反向遍历集合,nextIndex返回值表示集合中当前元素的索引位置。
int nextIndex();
// 如果是正向遍历集合,previousIndex返回值表示集合中当前元素的索引位置。
// 如果是反向遍历集合,previousIndex返回值表示集合中前一个元素的索引位置。
int previousIndex();
// 用元素e替换当前索引位置的元素
void set(E e);
// 在当前索引下一个位置添加元素e,再将索引位置加1,不遍历新添加的元素。
// 保证我们完整地遍历集合中原有的元素,而使用迭代器的删除,替换,添加操作,都不会影响本次遍历过程。
void add(E e);
}
这里有一点需要注意,当我们得到一个集合迭代器,进行遍历的时候,我们有可能在遍历过程中,用迭代器进行删除,添加,替换操作。要保证一点,就是这些操作不影响当前迭代过程,也就是说遍历得到的还是原来集合的数据。
抽象类AbstractList
AbstractList有一个非常重要的成员属性modCount。它用在多线程环境下,某个正在遍历的集合,是否被别的线程修改了,如果是,那么就会抛出ConcurrentModificationException异常。也就是说这个异常是在迭代器中抛出的。
添加元素
public boolean add(E e) {
add(size(), e);
return true;
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
add(E e) 方法是向集合末尾添加元素。而AbstractList 默认是不可修改的集合,需要自己手动复写add(int index, E element)方法,才能添加元素。
boolean addAll(Collection<? extends E> c) 这个方法是在AbstractCollection中实现的。
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
boolean modified = false;
for (E e : c) {
add(index++, e);
modified = true;
}
return modified;
}
private void rangeCheckForAdd(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
rangeCheckForAdd方法是检查索引是否越界的。然后遍历c集合,将每个元素添加到本集合中。
删除元素
删除元素的方法,大部分使用AbstractCollection类提供的实现。
public E remove(int index) {
throw new UnsupportedOperationException();
}
AbstractList是个不可修改的集合,所以这里做了限制。
更新元素
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
查询方法
1、boolean contains(Object o)和 boolean containsAll(Collection<?> c)方法采用AbstractCollection类提供的实现。
2、AbstractList提供了两个迭代器子类 Itr 和 ListItr ,之后我们将来分析它。
public Iterator<E> iterator() {
return new Itr();
}
public ListIterator<E> listIterator() {
return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
3、get(int index)方法强制子类必须实现。
abstract public E get(int index);
4、查找某个元素在集合中的位置,如果没找到就返回-1。这里就要用到ListIterator迭代器了,因为它可以集合中的位置索引。
public int indexOf(Object o) {
ListIterator<E> it = listIterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return it.previousIndex();
} else {
while (it.hasNext())
if (o.equals(it.next()))
return it.previousIndex();
}
return -1;
}
注意当我们正向遍历集合的时候,previousIndex()方法返回的就是当前元素的位置,而并不是前一个元素的位置。这个时候nextIndex()方法返回的是下一个元素的位置。
5、反向查找某个元素在集合中的位置,如果没找到就返回-1。
public int lastIndexOf(Object o) {
ListIterator<E> it = listIterator(size());
if (o==null) {
while (it.hasPrevious())
if (it.previous()==null)
return it.nextIndex();
} else {
while (it.hasPrevious())
if (o.equals(it.previous()))
return it.nextIndex();
}
return -1;
}
注意当我们反向遍历集合的时候,nextIndex()方法返回的就是当前元素的位置,而并不是下一个元素的位置。这个时候previousIndex()方法返回的是前一个元素的位置。
6、其它重要方法
int size()、boolean isEmpty()、Object[] toArray()、<T> T[] toArray(T[] a)方法都采用AbstractCollection类提供的实现。
public List<E> subList(int fromIndex, int toIndex) {
return (this instanceof RandomAccess ?
new RandomAccessSubList<>(this, fromIndex, toIndex) :
new SubList<>(this, fromIndex, toIndex));
}
AbstractList提供默认subList方法的实现。之后我们再来分析SubList和RandomAccessSubList这两个类。