集合就是存储用来存储一系列数据的一种数据结构。在这篇文章中会介绍集合的一些基本概念。
集合的基本接口是Collection接口,基本上所有集合都实现了这个接口。下面来看一下该集合
该接口定义了许多对集合的操作,通过这些操作,我们就可以很轻松的完成各种数据的增删改查
Iterator是一个接口,有4个方法,其中一个就是next方法,通过这个方法就可以很容易的访问集合中的元素
通过反复调用next方法,可以逐个访问集合中的每个元素。但是,如果到达了集合的末尾,next方法将抛出一个NoSuchElementException。因此,需要在调用next之前调用hasNext方法。如果迭代器对象还有多个可以访问的元素,这个方法就返回true。如果想要查看集合中的所有元素,就请求一个迭代器,当hasNext返回true时就反复地调用next方法。例如:
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer value = iterator.next();
System.out.println(value);
}
}
我们可以使用for each完成对集合循环遍历操作
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (Integer value : list) {
System.out.println(value);
}
}
对于实现了Iterable的对象,都可以使用for each循环。集合基本都可以使用for each,因为上面说明了集合类的基本接口是Collection,而Collection又实现了Iterable,所以可以使用,下面就是ArrayList的类图,可以发现最顶层就是Iterable接口
Iterable即可的内容如下
使用键值对存储数据的集合基本都实现了这个接口,Map接口定义了一些最基本的操作元素的方法,内容如下
我们直接看一下ArrayList里面的Itr类,这个类实现了Iterator接口
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
根据这个实现类,我们来理解一下这个接口。首先就是定义了2个变量
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
通过2个变量来表示索引。
下面就是hasNext,可以发现很简单,就是判断下一个要返回的索引是否等于元素个数
public boolean hasNext() {
return cursor != size;
}
下面就是next方法,忽略抛出异常的各种语句,可以发现就是返回当前cursor指向的值,然后将cursor+1,lastRet就表示为cursor的前一个索引
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
还有一个是remove方法,这个方法也很容易理解,就是将集合中索引为remove索引位置的元素移除,然后改变cursor的值,也很简单
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
上面是关于Iterator一直实现的思想,但是是针对数组的,其实对于链表以及其他类型也是类似的。
对于上面的代码,我们也可以看出remove是依赖于next方法的,因为lastRet的值必须由next来进行改变。
Java集合框架为不同类型的集合定义了大量接口,如图9-4所示。
可以发现集合有两个基本接口:Collection和Map。Collection存储形式为单个元素,Map就是按照键值对的方式来存储的(K-V)
表9-1展示了Java类库中的集合,并简要描述了每个集合类的用途。在表9-1中,除了以Map结尾的类之外,其他类都实现了Collection接口,而以Map结尾的类实现了Map接口。
我感觉对于java集合没有什么好说明的,这些内容应该属于数据结构,如果学习过数据结构,那么自己都可以写出这些集合,所以在后面介绍集合的文章中,将不会说明集合的基本概念,只会对源码进行debug,然后说明常用方法。