List
是一个有序(插入顺序)的Collection
(有时候也叫做序列)。可以包含重复的元素。除了从Collection
继承过来的方法外,还包含下面的操作:
- 位置访问:基于元素位置索引来操作元素。比如
get
、set
、add
、addAll
和remove
- 搜索:从List中搜索指定的元素,并且返回其位置索引。如
indexOf
和lastIndexOf
- 迭代:扩展
Iterator
提供利用List
序列特性的遍历操作。listIterator
方法返回此类迭代器 - 区间视图:
sublist
方法提供任意的区间操作。
Java平台提供了两种通用的List实现:ArrayList
和LinkedList
。
集合相关操作
继承自Collection
的相关集合操作,基本都符合你期望的样子。如果对这些不熟悉的话,请查看Collection接口。
需要提到的是,remove
操作将会移除List
中第一个出现的指定元素,add
和addAll
操作总是会将新的元素添加到原有List
末尾。因此,下面的方法可以将一个List
添加到另一个List
后面。
list1.addAll(list2);
上面这种方式将会改变list1
,可以通过下面的方式创建一个新的List
来包含list1
和list2
。
List<Type> list3 = new ArrayList<Type>(list1);
list3.addAll(list2);
位置访问和搜索操作
基本的位置访问操作是get
,set
,add
和remove
。set
和remove
操作在元素被覆盖和删除之前会先返回旧的元素。别的操作(indexOf和lastIndexOf)将会返回从List
中找到的第一个或者最后一个元素的索引。
addAll
操作将指定的Collection
中的所有元素,按照Collection
的迭代顺序插入到指定位置。此操作是Collection
中的addAll
的基于位置访问版本。
下面是一个小方法用来交换List
的两个不同位置的元素。
public static void swap(List<E> list, int i, int j) {
E tmp = list.get(i);
list.set(i, list.get(j));
list.set(j, tmp);
}
当然,这是一个多态算法:它可用来交换任意List的两个元素,而忽略了List的实现类型。下面是另外一个多态算法,使用了前面的swap
方法:
public static void shuffle(List<?> list, Random rnd) {
for (int i = list.size(); i > 1; i--) {
swap(list, i - 1, rnd.nextInt(i));
}
}
这个算法包含在Collections
中,用来随机打乱List
。实际上,如果List
的实现类型是LinkedList
,此算法的平均运行时间复杂度将会是O(n2)。因为链表基于位置的查找效率不高,为O(n)。在Collections
类中,shuffle
方法的实现如下:
注意到,
shuffle
方法会先去判断List
是否实现了RandomAccess
类型,而RandomAccess
实际上是一个空接口(不定义任何方法),基于名字也可以看出,它用来标记子类实现是否为随机访问。在Java类库中,List的实现者ArrayList
类实现了此接口,而LinkedList
没有实现此接口。因此,从这里也可以看出,由于链表并非随机访问类型,其直接使用基于位置的混淆效率将会低下。针对这种并非随机访问的List
,则先生成其数组形式的引用拷贝,对数组进行位置混淆后,再将打乱的数组写回List
。注意不同的
List
实现可能会影响到算法效率时,可以根据判断List
是否实现了RandomAccess
接口来区分是否可随机访问这种技巧。
迭代器
List
的iterator
方法返回Iterator类型的迭代器。同时,还提供给一个增强版ListIterator
,由listIterator
返回。ListIterator
可以让你从两个方向遍历List
,在迭代过程中修改列表,并且获取当前遍历的位置。
ListIterator
继承自Iterator
接口,继承的三个方法(hasNext
,next
,remove
)和Iterator
接口的方法做完全一样的事情。另外还包含了hasPrevious
和previous
方法,用来从后向前遍历。从方法名可以看出,其是和hasNext
和next
方法相对应的。
下面是一个标准的从后向前遍历List
的方法:
for (ListIterator<Type> it = list.listIterator(list.size()); it.hasPrevious(); ) {
Type t = it.previous();
……
}
注意到listIterator
方法有两种形式。无参数的形式返回一个位置位于List
开始处的ListIterator
,带一个int
参数的返回一个位于指定位置索引(index)的ListIterator
。这里的位置索引(index)指向被首次next
调用将会返回的元素。而index-1
指向被首次previous
调用的元素。在一个长度为n
的List
中,index
有n+1
个有效的值:从0到n。
直观地说,光标位置总是位于两个元素之间——一个由调用previous
返回的元素和一个由调用next
返回的元素。这n+1
个有效index
对应于n
个元素之间的n+1
个间隙。下图展示了一个包含四个元素的List
可以有五个可能的光标位置:
区间视图操作
区间视图操作subList(int fromIndex, int toIndex)
返回一个原有List
的部分List
视图,索引包括fromIndex
,不包括toIndex
。
注意:这个子List
并非原有List
的拷贝,实际上其为同一List
,只不过只给你看你想要的那部分。作用在原有List
上的操作将会影响到新的子List
。如果修改了原有List
,可能导致子List
紊乱。同样对子List
进行添加和删除将会影响到原有List
。
任何只需要考虑List
一部分的范围操作,都可以考虑用subList
来进行替代。比如,下面可以用来删除List
的一部分元素:
list.subList(fromIndex, toIndex).clear();
List
算法
Collections
类中的大部分算法都适用于List
,下面是这些算法的一个总结:
- sort——使用归并排序算法来对
List
进行排序 - shuffle——随机打乱
List
中的元素 - reverse——对
List
进行逆序操作 - rotate——以一个给定的距离旋转
List
中的所有元素 - swap—— 交换
List
中指定位置的元素 - replaceAll——将在
List
中所有出现的指定值替换为新的值 - fill ——用指定值覆盖
List
中所有元素 - copy——拷贝源
List
到墓道目的List
- binarySearch——使用二分查找算法在一个排好序的
List
中查找给定的元素 - indexOfSubList——返回
List
等于给定子List
的第一个出现位置索引
_ lastIndexOfSubList——返回List
中等于给定子List
的最后一个出现位置索引
以上文章参考:
http://docs.oracle.com/javase/tutorial/collections/interfaces/list.html