java设计了一套集合(也叫容器)类库,来支持最常用的数据结构,Java集合类库采用接口与实现分离的原则。下面主要梳理集合接口,集合类(包括集合抽象类和具体实现类)。
1 Java集合接口
Java的集合接口关系图如下:
集合有两个基本接口Collection和Map
(1) Collection接口的源码如下:
public interface Collection extends Iterable {
// Query Operations
int size();
boolean isEmpty();
boolean contains(Object o);
//返回迭代器对象,用来访问集合中的元素
Iterator iterator();
//返回集合的对象数组
Object[] toArray();
//添加元素
boolean add(E e);
//移除元素
boolean remove(Object o);
//判断传入集合是否被包含
boolean containsAll(Collection> c);
//与传入集合求交集
boolean retainAll(Collection> c);
boolean addAll(Collection extends E> c);
}
(2)Map用来存放键值对,Map接口源码如下:
public interface Map {
// Query Operations
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
//获取对应k的值,如果没有这个值,则返回null,K可以为null
V get(Object key);
// Modification Operations
//插入k和v,此处可以插入k为null的键值对,但是v不能为null
V put(K key, V value);
V remove(Object key);
// Bulk Operations
void putAll(Map extends K, ? extends V> m);
void clear();
// Views
/*--注意从下面三个返回的集中,可以删除元素,与此同时也删除了Map中的元素,但是不能添加元素---***/
//返回Map中所有K的Set集
Set keySet();
//返回Map中所有V的Collection集合
Collection values();
//整个键值对作为一个Set集返回
Set> entrySet();
interface Entry {
K getKey();
V getValue();
V setValue(V value);
boolean equals(Object o);
int hashCode();
}
// Comparison and hashing
boolean equals(Object o);
int hashCode();
}
注意,在Java中访问集合中某个位置元素,要使用迭代器(Iterator)。
(3)Iterator接口的源码如下:
public interface Iterator {
//返回将要访问的下一个对象,如果已经是集合的最后一个元素,将抛出NoSuchElementException错误
E next();
//由于上面方法抛出错误,因此在访问集合元素之前,先判断是否有下一个元素
boolean hasNext();
//移除元素之前,要先使用next方法定位到改元素;
void remove();
}
List是一个顺序排列集合接口,List在特定位置添加元素的方法有两种,一种是整数索引,一种是列表迭代器。
(4)List接口的源码如下:
public interface List extends Collection {
// Query Operations
//继承Collection方法,参考Collection源码分析
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator iterator();
........
// Positional Access Operations
//获取给定位置的元素
E get(int index);
//用新元素取代给定位置元素,返回原来的元素
E set(int index, E element);
//通过整数索引,在给定位置添加元素
void add(int index, E element);
//移除给定位置的元素
E remove(int index);
// Search Operations
//返回与给定元素相等的元素在列表中第一次出现的位置,如果没有返回-1
int indexOf(Object o);
//返回与给定元素相等的元素在列表中最后一次出现的位置,如果没有放回-1
int lastIndexOf(Object o);
// List Iterators
//返回一个列表迭代器
ListIterator listIterator();
//返回一个列表迭代器,第一次调用next后,返回的给定索引的元素
ListIterator listIterator(int index);
// View
//返回List的某个范围内的子集合
List subList(int fromIndex, int toIndex);
}
由于Collection有的子集合(如Set)是无序的,所以Iterator接口中无add方法,但是对于List子集合需要使用迭代器添加指定位置的元素,因此ListIterator继承Iterator,提供了add方法。
(5)ListIterator接口源码如下:
public interface ListIterator extends Iterator {
// Query Operations
//继承Iterator方法,参考Iterator源码分析
boolean hasNext();
E next();
//反向迭代列表时,判断是否有元素
boolean hasPrevious();
//返回前一个对象,如果已经是集合的第一个元素,将抛出NoSuchElementException错误
E previous();
//返回下一次调用next方法后,元素的索引
int nextIndex();
//返回下一次调用previous方法后,元素的索引
int previousIndex();
// Modification Operations
void remove();
void set(E e);
void add(E e);
}
Set接口和Collection接口的方法一样,这里Java为什么要定义一个新的接口?是为了从概念上区分集合与集,方面扩展。
SortedSet和SortedMap接口,顾名思义给开发者暴露了排序的方法,并可以返回某个范围内的子集
(6)SortedSet的源码如下:
public interface SortedSet extends Set {
//用于排序的方法,参考后续章节具体实现类
Comparator super E> comparator();
//下面三个方法,返回给定范围内的子SortedSet集
SortedSet subSet(E fromElement, E toElement);
SortedSet headSet(E toElement);
SortedSet tailSet(E fromElement);
E first();
E last();
}
(7)SortedMap的源码如下:
public interface SortedMap extends Map {
//用于排序的方法,参考后续章节具体实现类
Comparator super K> comparator();
//下面三个方法,返回给定范围内的子SortedMap
SortedMap subMap(K fromKey, K toKey);
SortedMap headMap(K toKey);
SortedMap tailMap(K fromKey);
//下面三个方法和Map接口中方法一样,参考Map接口源码
Set keySet();
Collection values();
Set> entrySet();
}
Java SE6引入了NavigableSet和NavigableMap接口,用来在有序集和Map中查找遍历方法
(8)NavigableSet源码如下:
public interface NavigableSet extends SortedSet {
E lower(E e);
E floor(E e);
.......
//下面三个方法主要返回给定范围内的子NavigableSet,boolean 标志是否包括边界值
NavigableSet subSet(E fromElement, boolean fromInclusive,
E toElement, boolean toInclusive);
NavigableSet headSet(E toElement, boolean inclusive);
NavigableSet tailSet(E fromElement, boolean inclusive);
//下面三个方法和SortedSet接口中方法一样,参考SortedSet接口源码
SortedSet subSet(E fromElement, E toElement);
SortedSet headSet(E toElement);
SortedSet tailSet(E fromElement);
}
(9)NavigableMap源码如下:
public interface NavigableMap extends SortedMap {
Map.Entry lowerEntry(K key);
K lowerKey(K key);
Map.Entry floorEntry(K key);
K floorKey(K key)
Map.Entry ceilingEntry(K key);
........
//下面三个方法,返回给定范围内的键的NavigableMap,boolean 表示是否包括边界
NavigableMap subMap(K fromKey, boolean fromInclusive,
K toKey, boolean toInclusive);
NavigableMap headMap(K toKey, boolean inclusive);
NavigableMap tailMap(K fromKey, boolean inclusive);
//下面三个方法,与SortedMap方法一样,参考SortedMap源码
SortedMap subMap(K fromKey, K toKey);
SortedMap headMap(K toKey);
SortedMap tailMap(K fromKey);
}
队列是在尾部添加一个元素,在头部删除一个元素。双端队列是在头部和尾部都可以删除元素
(10)Queue的源码如下:
public interface Queue extends Collection {
//当执行add往队列中添加元素时,如果队列没有满,则往队列尾部添加元素并返回true,否则add方法抛出异常,offer方法返回false
boolean add(E e);
boolean offer(E e);
//当执行remove移除队列中头部元素时,如果队列不空,则移除头部元素并返回true,否则remove方法抛出异常,poll方法返回false
E remove();
E poll();
//当执行element查看队列中头部元素时,如果队列不空,则返回队列中的头部元素,否则element方法抛出异常,peek方法返回null
E element();
E peek();
}
(11)Deque(双端队列接口)源码如下:
public interface Deque extends Queue {
//当给定的对象添加到双端队列的头部和尾部时,如果队列满了,则前两个方法抛出异常,后两个方法返回false
void addFirst(E e);
void addLast(E e);
boolean offerFirst(E e);
boolean offerLast(E e);
//当删除双端队列头部和尾部元素时,如果队列为空,则前两个方法抛出异常,后两个方法返回null
E removeFirst();
E removeLast();
E pollFirst();
E pollLast();
//当查询双端队列头部和尾部元素时,如果队列为空,则前两个方法抛出异常,后两个方法返回null
E getFirst();
E getLast();
E peekFirst();
E peekLast();
boolean removeFirstOccurrence(Object o);
boolean removeLastOccurrence(Object o);
// *** Queue methods ***
//参考Queue 中的add、offer方法说明
boolean add(E e);
boolean offer(E e);
//参考Queue 中的remove、poll方法说明
E remove();
E poll();
//参考Queue 中的element、peek方法说明
E element();
E peek();
// *** Stack methods ***
void push(E e);
E pop();
// *** Collection methods ***
//参考Collection 中的方法说明
boolean remove(Object o);
boolean contains(Object o);
public int size();
Iterator iterator();
Iterator descendingIterator();
}
RandomAccess接口用于监测List随机访问的效率,该接口没有方法,ArrayList继承了该接口。
(12)RandomAccess源码:
public interface RandomAccess {
}
2. Java集合类
前面的Java集合接口中有大量的方法,这些方法主要通过抽象类和具体类实现。其中抽象类主要实现接口中一部分通用的方法,具体类针对具体的类型实现具体的方法。
下面是Java集合类图:
2.1 Java集合抽象类
对于公用的方法可在集合抽象类实现,一些具体的方法可抽象化在继承的有具体特征的子类中实现。集合抽象类主要有AbstractCollection、AbstractMap
AbstractList、AbstractSet、AbstractQueue、AbstractSequentialList
这里以AbstractCollection源码为例分析一下:
AbstractCollection的源码如下:
public abstract class AbstractCollection implements Collection {
protected AbstractCollection() {
}
// Query Operations
//Collection接口中方法,可根据不同的集合,具体实现。
//迭代器方法和集合大小方法抽象。
public abstract Iterator iterator();
public abstract int size();
//下面所有的方法都在抽象类中实现
public boolean isEmpty() {
return size() == 0;
}
//用迭代器,访问逐次访问集合中的元素,判断是否包含给定的对象
public boolean contains(Object o) {
Iterator it = iterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return true;
} else {
while (it.hasNext())
if (o.equals(it.next()))
return true;
}
return false;
}
//逐次访问集合中的元素,转换集合中对象为数组
public Object[] toArray() {
//根据集合大小定义数组
Object[] r = new Object[size()];
Iterator it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext())
// fewer elements than expected
return Arrays.copyOf(r, i);
r[i] = it.next();
}
return it.hasNext() ? finishToArray(r, it) : r;
}
public T[] toArray(T[] a) {
// Estimate size of array; be prepared to see more or fewer elements
int size = size();
T[] r = a.length >= size ? a :
(T[])java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
Iterator it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) { // fewer elements than expected
if (a != r)
return Arrays.copyOf(r, i);
r[i] = null; // null-terminate
return r;
}
r[i] = (T)it.next();
}
return it.hasNext() ? finishToArray(r, it) : r;
}
//Integer.MAX_VALUE是int整形的最大取值2的31次方-1,这个常量用来控制集合的最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static T[] finishToArray(T[] r, Iterator> it) {
int i = r.length;
while (it.hasNext()) {
int cap = r.length;
if (i == cap) {
int newCap = cap + (cap >> 1) + 1;
// overflow-conscious code
if (newCap - MAX_ARRAY_SIZE > 0)
newCap = hugeCapacity(cap + 1);
r = Arrays.copyOf(r, newCap);
}
r[i++] = (T)it.next();
}
// trim if overallocated
return (i == r.length) ? r : Arrays.copyOf(r, i);
}
//返回集合的最大容量值
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError
("Required array size too large");
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
// 添加对象方法实现
public boolean add(E e) {
throw new UnsupportedOperationException();
}
//移除对象方法实现
public boolean remove(Object o) {
Iterator it = iterator();
if (o==null) {
while (it.hasNext()) {
if (it.next()==null) {
it.remove();
return true;
}
}
} else {
while (it.hasNext()) {
if (o.equals(it.next())) {
it.remove();
return true;
}
}
}
return false;
}
//批量操作方法实现
//判断传入集合是否被包含方法实现
public boolean containsAll(Collection> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
//添加传入集合方法实现
public boolean addAll(Collection extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
//移除传入集合方法实现
public boolean removeAll(Collection> c) {
boolean modified = false;
Iterator> it = iterator();
while (it.hasNext()) {
if (c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
//实现与传入集合求交集方法
public boolean retainAll(Collection> c) {
boolean modified = false;
Iterator it = iterator();
while (it.hasNext()) {
if (!c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
//对象转换为字符串
public String toString() {
Iterator it = iterator();
//如果集合中对象为null,返回"[]"
if (! it.hasNext())
return "[]";
//拼接字符串
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
}
2.2 Java集合具体实现类
我们项目中经常使用的具体类(Java集合类图中具体类)主要有LinkedList、ArrayList、HashSet、TreeSet、PriorityQueue、Array、Deque、HashMap、TreeMap,这些类的源码解析,见后续章节的分析;
下面是Java集合具体类的主要特征,如下表: