基于源码的Java集合框架学习① Iteretor以及List

本文从源码角度探讨Java集合框架,重点关注Iterator接口及其故障快速修复特性,以及List接口和相关抽象类,如AbstractList、AbstractSequentialList。内容包括集合的迭代、双向遍历、修改操作及Collection接口的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开始学习下java集合类的源码

参考:http://www.cnblogs.com/skywang12345/p/3323085.html

          JDK1.7中文版API

          JDK1.7源码

接口 Iterator

对集合进行迭代的迭代器。迭代器代替了 Java Collections Framework 中的 Enumeration。

迭代器与枚举有两点不同: 

  1. 迭代器允许调用方利用定义良好的语义在迭代期间从迭代器所指向的集合移除元素。
  2. 方法名称得到了改进。
public interface Iterator<e> {
  //如果仍有元素可以迭代,则返回 true。
  boolean hasNext();
  //返回迭代的下一个元素。
  E next();
  //从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作)。每次调用 next 
  //只能调用一次此方法。如果进行迭代时用调用此方法之外的其他方式修改了该迭代器所指向的集合,则迭代器的行为是不明确的。
  void remove();
}</e>

迭代器是 故障快速修复(fail-fast)的。这意味着,当另一个线程修改底层集合的时候,如果您正在用 Iterator 遍历集合,那么,Iterator就会抛出 ConcurrentModificationException (另一种 RuntimeException异常)异常并立刻失败 。

接口 ListIterator

列表迭代器,允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。ListIterator 没有当前元素;它的光标位置 始终位于调用 previous() 所返回的元素和调用 next() 所返回的元素之间。在长度为 n 的列表中,有 n+1 个有效的索引值,从 0 到 n(包含)。 

public interface ListIterator<e> extends Iterator<e> {
  void hasPrevious()
  Object previous()
  //返回对 next 的后续调用所返回元素的索引。(如果列表迭代器在列表的结尾,则返回列表的大小)。&nbsp;
  int nextIndex()
  //(如果列表迭代器在列表的开始,则返回 -1)。&nbsp;
  int previousIndex()
  //将指定的元素插入列表(可选操作)。该元素直接插入到 next 返回的下一个元素的前面(如果有),或者 previous 返回的下一个元素之后(如果有)。
  void add(E)
  //替换最后一次调用next()或者previous()返回的元素。在调用本方法前,不可调用add(E)和remove()方法。
  void set(E)
  boolean hasNext();
  E next();
  void remove();
}

相较于Iterator,ListIterator允许我们向前、向后两个方向遍历 List;在遍历时修改 List 的元素;遍历时获取迭代器当前游标所在位置。

接口 Collection

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

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

Collection 作为集合的一个根接口,定义了一组对象和它的子类需要实现的 15 个方法:

int size()
获取元素个数
boolean isEmpty()
是否个数为 0
boolean contains(Object element)
是否包含指定元素
boolean add(E element)
添加元素,成功时返回 true
boolean remove(Object element)
删除元素,成功时返回 true
Iterator<e> iterator()
获取迭代器
boolean containsAll(Collection<!--?--> c)
是否包含指定集合 c 的全部元素
boolean addAll(Collection<!--? extends E--> c)
添加集合 c 中所有的元素到本集合中,如果集合有改变就返回 true
boolean removeAll(Collection<!--?--> c)
删除本集合中和 c 集合中一致的元素,如果集合有改变就返回 true
boolean retainAll(Collection<!--?--> c)
保留本集合中 c 集合中两者共有的,如果集合有改变就返回 true
void clear()
删除所有元素
Object[] toArray()
返回一个包含集合中所有元素的数组
<t> T[] toArray(T[] a)
返回一个包含集合中所有元素的数组,运行时根据集合元素的类型指定数组的类型<br></t></e>

Collection不提供get()方法。如果要遍历Collectin中的元素,就必须用Iterator。 

类 AbstractCollection

此类提供了 Collection 接口的骨干实现,从而最大限度地减少了实现此接口所需的工作。

要实现一个不可修改的 collection,程序员只需扩展此类,并提供 iterator 和 size 方法的实现。(iterator 方法返回的迭代器必须实现 hasNext 和 next。)

要实现可修改的 collection,程序员还必须另外重写此类的 add 方法(否则,会抛出 UnsupportedOperationException),并且 iterator 方法返回的迭代器必须另外实现其 remove 方法。

按照 Collection 接口规范中的推荐,程序员通常应该提供一个 void (无参数)和 Collection 构造方法。

接口 List

有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。

与 set 不同,列表通常允许重复的元素。更正式地说,列表通常允许满足 e1.equals(e2) 的元素对 e1 和 e2,并且如果列表本身允许 null 元素的话,通常它们允许多个 null 元素。难免有人希望通过在用户尝试插入重复元素时抛出运行时异常的方法来禁止重复的列表,但我们希望这种用法越少越好。

List 接口在 iterator、add、remove、equals 和 hashCode 方法的协定上加了一些其他约定,超过了 Collection 接口中指定的约定。为方便起见,这里也包括了其他继承方法的声明。

List 接口提供了 4 种对列表元素进行定位(索引)访问方法。列表(像 Java 数组一样)是基于 0 的。注意,这些操作可能在和某些实现(例如 LinkedList 类)的索引值成比例的时间内执行。因此,如果调用方不知道实现,那么在列表元素上迭代通常优于用索引遍历列表。

List 接口提供了特殊的迭代器,称为 ListIterator,除了允许 Iterator 接口提供的正常操作外,该迭代器还允许元素插入和替换,以及双向访问。还提供了一个方法来获取从列表中指定位置开始的列表迭代器。

List 接口提供了两种搜索指定对象的方法。从性能的观点来看,应该小心使用这些方法。在很多实现中,它们将执行高开销的线性搜索。

List 接口提供了两种在列表的任意位置高效插入和移除多个元素的方法。

注意:尽管列表允许把自身作为元素包含在内,但建议要特别小心:在这样的列表上,equals 和 hashCode 方法不再是定义良好的。

某些列表实现对列表可能包含的元素有限制。例如,某些实现禁止 null 元素,而某些实现则对元素的类型有限制。试图添加不合格的元素会抛出未经检查的异常,通常是 NullPointerException 或 ClassCastException。试图查询不合格的元素是否存在可能会抛出异常,也可能简单地返回 false;某些实现会采用前一种行为,而某些则采用后者。概括地说,试图对不合格元素执行操作时,如果完成该操作后不会导致在列表中插入不合格的元素,则该操作可能抛出一个异常,也可能成功,这取决于实现的选择。此接口的规范中将这样的异常标记为“可选”。  

List 中除了继承 Collection 的一些方法,还提供以下操作:

在 list 中的位置进行操作,比如说 get, set, add, addAll, remove;
搜索:从 list 中查找某个对象的位置,比如 indexOf, lastIndexOf;
迭代:使用 Iterator 的拓展版迭代器 ListIterator 进行迭代操作;
范围性操作:使用 subList 方法对 list 进行任意范围的操作,由于 subList 持有 List 同一个引用,所以对 subList 进行的操作也会影响到原有 List。<br>

类 AbstractList

此类提供 List 接口的骨干实现,从而最大限度地减少了实现“随机访问”数据存储(如数组)支持的接口所需的工作。对于连续的访问数据(如链表),应优先使用 AbstractSequentialList,而非此类。

要实现不可修改的列表,只需扩展此类,并提供 get(int index) 和 size() 方法的实现。

要实现可修改的列表,还必须另外重写 set(int index, Object element) 方法,否则将抛出 UnsupportedOperationException。如果列表为可变大小,则程序员必须另外重写 add(int index, Object element) 和 remove(int index) 方法。

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
 protected transient int modCount
//已从结构上修改 此列表的次数。从结构上修改是指更改列表的大小,或者以其他方式打乱列表,使正在进行的迭代产生错误的结果。
//此字段由 iterator 和 listIterator 方法返回的迭代器和列表迭代器实现来使用。如果意外更改了此字段中的值,则迭代器(或列表迭代器)将抛出 ConcurrentModificationException 来响应 next、remove、previous、set 或 add 操作。在迭代期间面临并发修改时,它提供了快速失败 行为,而不是非确定性行为。
 boolean add(E o) 
//将指定的元素追加到此 List 的尾部(可选操作)。 
 void add(int index, E element) 
//在此列表中指定的位置插入指定的元素(可选操作)。 
 boolean addAll(int index, Collection<? extends E> c) 
//将指定 collection 中的所有元素插入此列表的指定位置(可选操作)。 
 void clear() 
//从此 collection 中移除所有元素(可选操作)。 
 boolean equals(Object o) 
//将指定的对象与此列表进行相等性比较。 
abstract  E get(int index) 
//返回此列表中指定位置处的元素。 
 int hashCode() 
//返回此列表的哈希码值。 
 int indexOf(Object o) 
//返回此列表中首次出现指定元素的索引,如果列表中不包含此元素,则返回 -1。 
 Iterator<E> iterator() 
//返回以正确顺序在此列表的元素上进行迭代的迭代器。 
 int lastIndexOf(Object o) 
//返回此列表中最后出现指定元素的索引,如果列表中不包含此元素,则返回 -1。 
 ListIterator<E> listIterator() 
//返回此列表中的元素的迭代器(按适当顺序)。 
 ListIterator<E> listIterator(int index) 
//从列表中的指定位置开始,返回此列表中的元素的列表迭代器(按适当顺序)。 
 E remove(int index) 
//移除此列表中指定位置处的元素(可选操作)。 
protected  void removeRange(int fromIndex, int toIndex) 
//从此列表中移除其索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。 
 E set(int index, E element) 
//将此列表中指定位置的元素替换为指定的元素(可选操作)。 
 List<E> subList(int fromIndex, int toIndex) 
//返回此列表 fromIndex(包括)和 toIndex(不包括)之间部分的视图。 
}

类 AbstractSequentialList

  • 此类提供了 List 接口的骨干实现,从而最大限度地减少了实现受“连续访问”数据存储(如链接列表)支持的此接口所需的工作。对于随机访问数据(如数组),应该优先使用 AbstractList,而不是先使用此类。
  • 从某种意义上说,此类与在列表的列表迭代器上实现“随机访问”方法(get(int index)、set(int index, Object element)、set(int index, Object element)、add(int index, Object element) 和 remove(int index))的 AbstractList 类相对立,而不是其他关系。
  • 要实现一个列表,程序员只需要扩展此类,并提供 listIterator 和 size 方法的实现即可。对于不可修改的列表,程序员只需要实现列表迭代器的 hasNext、next、hasPrevious、previous 和 index 方法即可。
  • 对于可修改的列表,程序员应该再另外实现列表迭代器的 set 方法。对于可变大小的列表,程序员应该再另外实现列表迭代器的 remove 和 add 方法。
void add(int index, E element) 
在此列表中的指定位置上插入指定的元素。 
boolean addAll(int index, Collection<? extends E> c) 
在此列表中指定的位置上插入指定 collection 中的所有元素。 
E get(int index) 
返回此列表中指定位置上的元素。 
Iterator<E> iterator() 
返回在此列表中的元素上进行迭代的迭代器(按适当顺序)。 
abstract  ListIterator<E> listIterator(int index) 
返回在此列表中的元素上进行迭代的列表迭代器(按适当顺序)。 
E remove(int index) 
移除此列表中指定位置上的元素。 
E set(int index, E element) 
用指定的元素替代此列表中指定位置上的元素。 
  • 支持 RandomAccess 的对象,遍历时使用get比迭代器更快。而AbstractSequentialList只支持迭代器按顺序访问,不支持RandomAccess,所以遍历 AbstractSequentialList 的子类,使用 for 循环 get() 的效率要 <= 迭代器遍历。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值