List(JDK1.7)(1)
与Set不同, List允许重复的元素。即 e1.equals(e2)。
部分方法定义
- int size();
返回列表中元素的个数,如果超过Integer.MAX_VALUE,就返回Integer.MAX_VALUE
- boolean isEmpty();
- boolean contains(Object o);
对于目标元素o, 如果列表中至少存在一个元素e:o==null? e==null ; o.eqauls(e)。
如果目标元素不可比较,将会抛出异常:ClassCastException.
如果目标元素为null,并且该列表不允许null元素,则抛出异常:NullPointerException.
- Iterator<E> iterator();
- Object[] toArray();
以恰当的顺序返回列表中的所有元素。
返回的数组是安全的,因为它的引用不是由该列表维护的。也就是说,该方法必须申请一个新的数组,即使list本身就是基于数组的。因此,调用者可以自由地修改返回的数组。
该方法作为一个桥梁,建立起基于数组和基于集合的API。
- <T> T[] toArray(T[] a);
返回数组的运行时类型是指定的数组类型。
如果列表恰好是该类型的,就会直接返回。否则,必须申请一个新数组,新数组的大小恰好就是列表的size。
如果列表是指定类型的,并且数组中还有剩余空间,则未使用的数组位置全部置null。——这一点很有用,因为可以判断列表的长度。前提是调用者知道该list不会包含任何null元素。
- boolean add(E e);
支持该操作的List,可能会限制允许加入该list的元素。比如,有些list可能会拒绝添加null作为元素,而其他list有可能限制元素的类型。
UnsupportedOperationException, 如果该List不支持add方法。
ClassCastException, 指定元素的类class,不允许它被添加到该list中。
NullPointerException,如果指定元素是null,并且该List不允许null元素。
IllegalArgumentException,如果该元素的某些属性,不允许它被添加到该list中。
- boolean remove(Object o);
删除第一次出现的那个元素,即下标最小的: o==null ? get(i )==null : o.eqauls(get(i );
如果列表中不包含这样的元素,就不变。
ClassCastException,如果指定元素的类型无法与list匹配。
NullPointerException, 如果指定元素是null,并且list不允许null元素。
UnsupportedOperationException,list不支持remove方法。
- boolean containsAll(Collection<?> c);
如果列表中包含了指定collection中的所有元素,返回true。
ClassCastException,如果指定collection中的一个或多个元素的类型与该list不匹配
NullPointerException,指定collection中包含一个或多个null,而list不允许null元素。
- boolean addAll(Collection<? extends E> c);
UnsupportedOperationException
ClassCastException
NullPointerException
IllegalArgumentException
- boolean addAll(int index, Collection<? extends E> c);
在指定的下标处插入指定collection中的所有元素。
IndexOutOfBoundsException,如果下标超出范围。
- boolean removeAll(Collection<?> c);
删除list中所有在c中出现的元素。
- boolean retainAll(Collection<?> c);
保留指定集合中出现的所有元素。
NullPointerException, 如果list中包含一个null,而指定的collection是不允许null的时候。
ClassCastException
- void clear();
- boolean equals(Object o);
两个list相等的条件是:他们包含相同的元素,以相同的顺序。
- int hashCode();
- E get(int index);
- E set(int index, E element); //替换已有下标处的元素
- void add(int index, E element);
- E remove(int index);
- int indexOf(Object o);
如果存在,就返回第一次出现的下标。如果不存在,返回-1.
- int lastIndexOf(Object o);
- ListIterator<E> listIterator();
- ListIterator<E> listIterator(int index); //从指定的下标开始遍历
- List<E> subList(int fromIndex, int toIndex);
返回一个视图。包含左下标,不包含右下标。
返回的List是基于原list的,所以在返回的list中进行的非结构性修改会在原list中体现,反之亦然。
任何针对局部范围list的操作,都可以通过传递一个subList视图来代表整个list。例如,下列语句删除了list中的部分元素:
list.subList(from, to).clear();
ArrayList
List接口的一种可调整大小的基于数组的实现。实现了所有可选的list操作,也允许所有元素,包括null。
另外,该类还提供了操纵底层实现数组的大小的方法。
该类和Vector类基本是一样的,除了ArrayList是非同步的。
以常数时间运行的方法:size, isEmpty, get, set, iterator, listIterator。摊销的常数时间,即O(n ):add。粗略来说,其他方法的运行时间都是线性的。常数因子比起LinkedList要小。
每个ArrayList的实例都有一个容量capacity。这是底层数组的大小。通常,容量至少要和List的大小一样大。因为增加一个元素有常数的摊销时间,所以没有明确规定增长策略的细节。
在增加大量元素之前扩容的一个办法是使用ensureCapacity操作,这可以减少容量调整的次数。
注意ArrayList是非同步的。如果多线程同时访问同一个ArrayList实例,并且至少有一个线程修改了列表结构,就必须要有外部的同步机制。通常通过同步某些封装了该list的对象来实现,如果没有这样的对象,该list就应该使用Collections.synchronizedList()来包装。最好在创建时就这样做,可以避免对该list的意外的非同步访问。(结构性修改是指,增加或删除一个或多个元素,或者调整了底层数组的大小,只修改了元素的值不是结构性修改)。
ArrayList中的iterator()方法和listIterator()返回的迭代器都是快速失败的。如果在创建了该迭代器之后的任意时间对list进行了结构性修改,除了通过iterator本身提供的方法之外,该Iterator都会抛出一个ConcurrentModificationException异常。面对同时发生的修改,iterator会快速干脆地失败,而不是无法确定未来的冒险的、非确定性的行为。
注意,iterator提供的快速失败机制并不能保证线程安全。快速失败机制应该只用于检测bug。
AbstractList源码
抽象类实现了部分方法。
ArrayList源码细节
ArrayList继承自AbstractList抽象类。
成员变量
构造方法
get()方法
set()方法
add()方法
扩容
contains()方法
remove()方法
clear()方法
clone()方法
转换为数组
迭代器 iterator 和 listIterator
【关于Itr中的remove()方法】
注意到lastRet表示上一次读取的位置,当这个位置为-1时,remove方法抛出IllegalStateException。而这个位置 为-1的情况,一个是初始化时,还未调用过next(),另一个是在调用了remove()方法后。所以,在这两种情况下是不能调用remove()方法的,即remove()方法不能连续调用,必须和next()结合,先next()后remove()。
另外,在删除元素时,会同步更新iterator中的expectedModCount,这样保持和List中的modCount的一致,从而使得checkForComodification()检测通过,本质上并不是线程同步的,当多个Iterator同时访问同一个List时,仍然是不安全的。
【ListItr】
在Itr的基础上,增加了向前遍历的方法,相当于一个双向遍历器。还增加了set()和add()方法,使得遍历器不仅可以删除元素,还可以修改和增加元素。
特别注意的,add()方法和remove()方法都会修改lastRet值为-1,因此需要读取lastRet的方法,譬如set(),remove()都不能在这两个方法后面调用,需要先调用一次next()方法。
List的add()和remove()方法都是结构性的修改,所以迭代器中的add()和remove()方法需要同步更新modCount的值,否则会在下一次增删改查操作时,检测到不相同,而抛出ConcurrentModificationException。