今天开始,要说Java内,非常重要的一个东西,就是集合,java著名的集合框架。
Part1:将Java集合框架的接口和类库分开!
我们来举一个关于队列接口,Queue的例子:
队列接口的最简单形式可能是这样:
public interface Queue<E>
{
void add(E element);
E remove();
int size();
}
那我们就可以通过Implements来实现它:
public class CircularArrayQueue<E> implements Queue<E>
{
private int head;//如果是LinkListQueue这里int换成Link
private int tail;
CircularArrayQueue(int capacity){...};
public void add(E element);
public E remove();
public int size();
private E[] elements;
}
只有在构建集合对象时,使用具体的类才有意义。这时候,我们可以是使用接口类型存放集合的引用。
Queue<Customer> expressLane = new CircularArrayQueue<>(100);
expressLane.add(new Customer("Harry"));
利用这种方式,我们可以有一些方便,比如说存在两个实现Queue的类,一个是LinkedListQueue,另一个是CircularArrayQueue。我们拿上面的例子来说,如果我们觉的LinkedListQueue是个更好的选择,那我们只需要将代码修改为:
Queue<Customer>expressLane = new LinkedListQueue<>();
expressLane.add(new Customer("Harry"));
在API文档中,会发现另外一组名字以Abstract开头的类,例如,AbstractQueue,这是集合框架中的为类库实现者而设计的。如果想自己实现自己的队列类,会发现拓展AbstractQueue类要比实现Queue接口中的所有方法轻松的多。
Part2:Collection接口和迭代器:
在Java类库中,集合类的基本接口是Collection接口。这个接口有两个基本方法:
public interface Collection<E>
{
boolean add(E element);
Iterator<E> iterator();
...
}
add方法顾名思义,而迭代器方法则是用于返回一个实现了Iterator接口的对象。可以使用这个迭代器对象依次访问集合中的元素!
Iterator接口包含四个方法:
public interface Iteratoe<E>
{
E next();
boolean hasNext();
void remove();
default void forEachRemanining(Consumer<? super E>action);
}
通过反复调用next方法,可以逐个访问集合中的每个元素。但是,如果到达了集合的末尾,next方法将抛出一个NoSuchElementException异常。因此,需要在使用next方法之前,使用hasnext方法。
Collection<String> c = ...;
Iterator<String> iter = c.iterator();
while(iter.hasNext())
{
String element = iter.next();
//code....
}
还可以用for…each循环可以更加简练的表示同样的循环操作:
for(String element : c)
{
do something with element;
}
编译器简单地将“for each”循环翻译为带有迭代器的循环。
“for each”循环可以与任何实现了Iterable接口的对象一起工作,这个接口只包含一个抽象方法:
public interface Iterable<E>
{
Iterator<E> iterator();
...
}
Collection接口拓展了Iterable接口。因此,对于标准类库中的任何集合都可以使用”for each”循环。
在Java的迭代器中,查找操作与位置变更是紧密相连的。查找一个元素唯一的方法是调用next,而执行查找操作的同时,迭代器位置会随之向前移动。
因此,应该将Java迭代器认为是位于两个元素之间。当调用next时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用。
Iterator接口的remove方法将会删除上次调用的next方法时返回的元素。
更重要的是,next方法和remove方法的调用具有互相依赖性。 如果调用remove之前,没有调用next将是不合法的。那样做,将会抛出一个IllegalStateEception的异常!