系列文章:
前言
从本篇开始,我将开始Java集合系列的梳理,本文先对集合框架中涉及到的接口,架构,类等做一个总体展示,后面的文章中再结合源码分别剖析具体集合,希望能用两个月的时间完成Java集合系列文章。
Java最初版本只为最常用的数据结构提供了很少的一组类:Vector
,Stack
,Hashtable
,BitSet
与Enumeration
接口。Enumeration
接口定义了从一个数据结构得到连续数据的手段,实现了遍历集合,现在已经被迭代器Iterator
取代了。JDK1.2
版本后,Java开始提供了一组集合框架,完善了Java数据结构。
Java集合包含了以下常用的数据结构:集合(Set
,无序不可重合的集合)、列表(List
,有序可重复的集合)、队列(Queue
,队列集合,JDK1.5
后加入)、栈(Stack
)、数组、映射表(Map
,具有映射关系的集合)等。Java集合类库构成了集合类的框架,包含了大量的接口,抽象类,框架图如下所示:
从上图可以发现,Java集合主要由三个接口派生出来,分别是Iterator
,Collection
,Map
,而Collection
又派生出List
,Set
,Queue
等,可以说是Java集合的根接口了。
迭代器接口(Iterator)
首先我们来看Iterator
接口,主要用来遍历集合对象中的元素,其包含三个方法:
public interface Iterator<E>
{
E next(); // 返回将要访问的下一个对象
boolean hasNext(); // 如果存在可访问的元素,返回true
void remove(); // 删除上次访问的对象,必须紧跟在访问一个元素之后执行
}
遍历元素
通过反复调用next
方法,可以逐个访问集合中的每个元素,如果到达了集合的末尾,next
方法将抛出一个NoSuchElementException
,因此在调用next
方法之前需要调用hasNext
方法判断是否到达集合末尾。使用方法如下:
Collection<String> c = ...
Iterator<String> iter = c.iterator();
while(iter.hasNext())
{
String ele = iter.next();
...
}
从Java JDK1.5
之后,可以用for循环来执行上述循环操作了,更加简洁,代码如下:
for(String ele : c)
{
...
}
编译器将“for each”循环翻译为带有迭代器的循环,“for each”循环适用于任何实现了Iterable
接口的对象,Iterable
接口只包含了一个方法:
public interface Iterable<E>
{
Iterator<E> iterator();
}
Collection
接口扩展了Iterable
接口,因此Java集合中只要实现了Collection
集合的接口都可以使用“for each”循环。
删除元素
Iterator
接口的remove
方法删除上次调用next
方法返回的元素,与遍历元素类似,删除某元素前,需要判断该元素是否有意义。正确的使用方法如下:
Collection<String> c = ...
Iterator<String> iter = c.iterator();
iter.next();
iter.remove();
可以看到先调用next
方法返回想要删除的元素,再删除之。如果上次访问之后,集合已经发生变化,再调用remove
方法,将抛出一个IllegalStateException
。
以下的使用方法都是错误的:
- 没有调用
next
方法
Iterator<String> iter = c.iterator();
iter.remove();
- 调用一次
next
方法,删除连续两个元素
Iterator<String> iter = c.iterator();
iter.next();
iter.remove();
iter.remove();
集合接口 (Collection)
方法列表
Collection
主要包含了集合的基本操作和属性,有两大分支List
和Set
。其中定义了很多方法供其子类实现,以实现数据操作,方法列表如下图所示:
从方法列表中可以看出,Collection
接口主要的功能有:添加元素,删除元素,清空集合等。
iterator
方法用于返回一个实现了Iterator
接口的对象,使用此对象遍历集合元素。
List接口
List是一个元素有序,可重复的集合,每一个元素都有它的索引,可以通过索引来访问指定位置的集合元素。由于List是有序集合,因此List接口中添加了一些根据索引值来操作的方法。List的实现类有LinkedList
, ArrayList
, Vector
, Stack
。
// List接口与Collection相比新增的方法
abstract void add(int index, E object)
abstract boolean addAll(int index, Collection<? extends E> collection)
abstract E get(int index)
abstract int indexOf(Object object)
abstract int lastIndexOf(Object object)
abstract ListIterator<E> listIterator(int index)
abstract ListIterator<E> listIterator()
abstract E remove(int index)
abstract E set(int index, E object)
abstract List<E> subList(int start, int end)
Set接口
Set
是一个不允许有重复元素的集合,其方法和Collection
相比没有区别,当添加重复元素时会返回false,Set的实现类有HashSet
和TreeSet
,而HashSet
又依赖于HashMap
,实际上是通过HashMap
实现的;TreeSet
又依赖于TreeMap
,实际上是通过TreeMap
实现的。
Queue接口
Queue接口模拟了队列这种数据结构,先进先出(FIFO
),其方法摘要如下图所示:
Map接口
Map是一个具有映射关系的集合,以“key-value
”保存数据。把Map集合里的Key值放在一起就构成了类似于Set的集合,Key值没有顺序,且不允许重复,Map接口的KeySet()
方法用于返回Key值构成的Set集合;而把Map集合里的Value值放在一起就构成了类似于List的集合,元素之间可以重复。其方法摘要如下:
AbstractCollection类
其定义如下:
public abstract class AbstractCollection<E> extends Object implements Collection<E> {}
AbstractCollection
类是一个抽象类,提供了 Collection
接口的大部分实现,以最大限度地减少了实现此接口所需的工作,除了iterator
和 size
方法。
要实现一个不可修改的 collection
,我们只需扩展此类,并实现 iterator
和 size
方法(iterator
方法返回的迭代器必须实现 hasNext
和 next
方法)。
要实现可修改的 collection
,我们必须另外重写此类的 add
方法(否则,会抛出 UnsupportedOperationException
),iterator
方法返回的迭代器还必须另外实现其 remove
方法。
AbstractList类
其定义如下:
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {}
AbstractList
类是一个抽象类,继承了AbstractCollection
类,并实现了List接口,提供了 List 接口的大部分实现,对于连续的访问数据(如链表),应优先继承 AbstractSequentialList
,而不是此类。
要实现不可修改的列表,我们只需扩展此类,并提供 get(int)
和 size()
方法的实现。
要实现可修改的列表,我们必须另外重写 set(int, E)
方法(否则将抛出 UnsupportedOperationException
)。如果列表为可变大小,则也要重写 add(int, E)
和 remove(int)
方法。
AbstractSet类
其定义如下:
public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> {}
AbstractSet
类是一个抽象类,继承了AbstractCollection
类,并实现了Set接口,提供了 Set 接口的大部分实现。
工具类及其它接口
ListIterator接口
其定义如下:
public interface ListIterator<E> extends Iterator<E> {}
ListIterator
接口继承于Iterator
接口,专门用于各种List类型的访问,其方法摘要如下图所示:
从上图可以看到,ListIterator
接口提供了前向/后向遍历的方法,同时也提供了add()
方法,用于添加元素,ListIterator
还可以通过nextIndex()
和previousIndex()
定位当前索引位置。
Arrays
此类包含用来操作数组(比如排序和搜索)的各种方法。主要方法有:
static <T> List<T> asList(T... a) // 返回一个受指定数组支持的固定大小的列表。
static int binarySearch(...) // 二分查找,数组需要有序
static void sort(...) // 排序
copyOf(...) // 复制数组
copyOfRange(...) // 复制部分数组
Collections
此类完全由在 collection
上进行操作或返回 collection
的静态方法组成。主要方法有:
static <T> int binarySearch(...) // 二分查找
sort(...) // 对list集合排序
max(...) / min(...) // 对集合取最大值/最小值
static void reverse(List<?> list) // 反转指定列表中元素的顺序。
static void swap(List<?> list, int i, int j) // 在指定列表的指定位置处交换元素。
....
Arrays和Collections工具类的具体API可以参考JDK文档,此处只列出了一小部分