java集合(1):集合框架体系之Collection接口及迭代器Iterator接口

时间:2021-11-18 19:35:42

前言

集合跟数组一样,也是容器。集合与数组的区别:

  1. 数组长度固定,存同一类型元素,可以存基本数据类型。
  2. 集合长度可变,可存不同类型元素,存储的都是对象, 基本数据类型会自动装箱为对象类型。

jdk1.0版本中提供的可用容器比较少,到了jdk1.2版本,为了满足更多的需求,出现了更多的集合来完成不同的需求。这些容器如何区分?每一种容器的数据结构不同。

学习集合体系原则:看顶层,用底层。

正文

一,集合概述

  1. 集合体系有一个完整的框架图,如下图。其中该体系最顶层的就是Collection接口,该接口中定义了集合体系中最共性的功能:增删元素等。
  2. 集合中的元素取出方式也是所有集合类必须的具备的功能,将这些操作抽取出来,形成一个公共的接口Iterator,所有集合类中都有一个内部类来实现这个接口,并在集合类(外部类)中提供一个返回内部类对象的方法,从而调用内部类的迭代器方法。
  3. 集合中存的是对象的引用(地址)。
  4. 集合中什么是重复元素?即同一个引用(地址)。

    java集合(1):集合框架体系之Collection接口及迭代器Iterator接口

二,Collection接口

  • Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递collection,并在需要最大普遍性的地方操作这些 collection。

  • 所有通用的 Collection 实现类(通常通过它的一个子接口间接实现 Collection)应该提供两个“标准”构造方法:一个是 void(无参数)构造方法,用于创建空 collection;另一个是带有 Collection 类型单参数的构造方法,用于创建一个具有与其参数相同元素新的 collection。实际上,后者允许用户复制任何 collection,以生成所需实现类型的一个等效 collection。尽管无法强制执行此约定(因为接口不能包含构造方法),但是 Java 平台库中所有通用的 Collection 实现都遵从它。

三,迭代器(重点)

上面说到,Collection接口定义了集合这一数据结构该有的最基本的方法,包括下列方法:

  • 添加元素的方法:add(),addAll()。
  • 删除元素的方法:remove(),removeAll(),retainAll(),clear() 。
  • 判断元素是否在集合中的方法:contains(),containsAll()。
  • 集合的属性方法:isEmpty(),size(),hashCode()。
  • 判断集合对象是否相同的方法:equals()。
  • 获取迭代器对象的方法:iterator()。

这里重点介绍一下iterator()这个方法,这个方法的原型:

Iterator<E> iterator()

该方法返回的是Iterator接口类型,该接口定义了3个方法

  • hasNext() ,如果仍有元素可以迭代,则返回 true。
  • next() ,返回迭代的下一个元素。
  • remove(),从迭代器指向的 collection 中移除迭代器返回的最后一个元素。

下面,我们来看看集合的实现类ArrayList是怎么实现集合接口和迭代器接口的,下面是部分源码:

public class ArrayList<E> implements List<E>{
//省略一些成员变量和方法
public Iterator<E> iterator() { // 这是重写的iterator()方法
return new Itr(); // 返回私有内部类对象
}

private class Itr implements Iterator<E> { // 内部类实现Iterator接口
// 省略内部类的成员变量和方法
public boolean hasNext() {...}
public E next() {...}
public void remove() {...}
}
}

所以,我们在对集合进行迭代的时候,会进行类似下面的操作:

List<String> list = new ArrayList<>();  // 创建集合

list.add("jimmy1"); // 添加元素
list.add("jimmy2");
list.add("jimmy3");
list.add("jimmy4");

Iterator<String> itr = list.iterator(); // 获得迭代器对象

while (itr.hasNext()) { // 使用迭代器对象的方法进行迭代
String string = itr.next();
System.out.println(string);
}

当然,如果只是迭代获得元素,还可以用更简单的foreach循环。

我们还说过,有时候我们需要在迭代的时候操作元素,如增删改操作。但是获得迭代器时长度是已知的,迭代中改变集合长度会造成混乱,一些Iterator可能会抛出ConcurrentModificationException异常。针对这种情况,List接口使用了新的迭代器ListIterator,该迭代器继承了Iterator迭代器,来看一下:

public interface ListIterator<E> extends Iterator<E>

同样的,ArrayList等实现类在实现该接口也是使用内部类来实现的,这样,List集合就能实现边迭代边修改元素了。下面是ListIterator的实现类。

public class ArrayList<E> implements List<E>{
//省略一些类成员变量和方法

public Iterator<E> iterator() { // 这是重写的iterator()方法
return new Itr(); // 返回私有内部类对象
}

public ListIterator<E> listIterator() { // 这是重写的listIterator()方法
return new ListItr(0); // 返回私有内部类对象
}

private class Itr implements Iterator<E> { // 内部类实现Iterator接口
// 省略内部类的成员变量和方法
public boolean hasNext() {...}
public E next() {...}
public void remove() {...}
}

// 内部类实现ListIterator接口
private class ListItr extends Itr implements ListIterator<E> {
// 类实现
}
}

总结

集合很常用,本文介绍了最顶层的接口Collection,并且重点介绍了同样是所有集合的共性的迭代器。