JDK容器类里的迭代器模式学习
2014-03-19 20:07
543 查看
迭代器模式又叫游标模式,是提供一种方法用来访问容器内的元素,而不用暴露容器内部的实现。
这样有2个明显的好处:
1 容器内部的结构发生变化时,如果迭代器本身不发生变化,则外面使用迭代器的业务代码不用修改。
2 如果我们需要提供多于一种的迭代方式,则只需增加迭代器,不用修改容器类。
这2点也正好满足设计模式所要求的单一职责条例。
我们这里重点分析下JDK容器类(ArrayList和LinkedList)使用到的迭代器模式。
JDK提供的迭代器接口为:
ArrayList是以数组组织的List,其返回Iterator的接口如下:
ArrayList还提供了一种双向迭代器,其实现如下:
LinkedList的以双向链表作为数据的组织方式,其内部迭代器的实现和ArrayList的类似,只是访问元素要遍历。
从上面的实现可以看出:
1 我们使用的时候,虽然不知道内部是如何存储的,但我们还是很方便的可以操作容器类的元素,如果内部数组组织方式变了,只要提供正确的迭代器,我们程序不需要修改。
2 增加一种新的迭代器也很方便,不需要对容器类进行修改,内部类的方式只是提供了实现方便,迭代器的实现完全可以独立出来。
这样有2个明显的好处:
1 容器内部的结构发生变化时,如果迭代器本身不发生变化,则外面使用迭代器的业务代码不用修改。
2 如果我们需要提供多于一种的迭代方式,则只需增加迭代器,不用修改容器类。
这2点也正好满足设计模式所要求的单一职责条例。
我们这里重点分析下JDK容器类(ArrayList和LinkedList)使用到的迭代器模式。
JDK提供的迭代器接口为:
public interface Iterator<E> { boolean hasNext();//判断是否还有元素 E next();//返回下一个元素 void remove();//删除元数 }
ArrayList是以数组组织的List,其返回Iterator的接口如下:
public Iterator<E> iterator() { return new Itr();//Itr是ArrayList内部类,其实现代码如下: } //按照Java的语法规则,内部类可以访问主类的属性和方法。 private class Itr implements Iterator<E> { int cursor;//当前元素的索引 int lastRet = -1;//遍历过程中当前元素的前一个元素,-1表示没有这个元素 int expectedModCount = modCount;//迭代器迭代过程中主类的结构(增加和删除元素等)变更次数 //size表示主类里面元素个数,hasNext判断当前游标有没有超过元素个数,没超过,则可以继续遍历 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;//cursor增加1 return (E) elementData[lastRet = i];//返回第cursor+1个元素 } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification();//迭代期间主类的结构是否发生变化,如果发生变化,则抛出异常 try { ArrayList.this.remove(lastRet);//删除前一个元素 cursor = lastRet;//cursor指向前一个元素 lastRet = -1;//表示目前没有前一个元素 expectedModCount = modCount;//更正变更次数 } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException();//抛出并发修改异常 } } //判断迭代期间主类的结构是否发生变化 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
ArrayList还提供了一种双向迭代器,其实现如下:
//提供双向迭代器 public ListIterator<E> listIterator(int index) { if (index < 0 || index > size)//判断下标是否合法 throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); } private class ListItr extends Itr implements ListIterator<E> { ListItr(int index) { super(); cursor = index;//当前元素小标 } //判断是否有前向元素 public boolean hasPrevious() { return cursor != 0; } //返回下一个指标 public int nextIndex() { return cursor; } //返回前一个元素下标 public int previousIndex() { return cursor - 1; } //返回前一个元素 @SuppressWarnings("unchecked") public E previous() { checkForComodification();//判断变更次数 int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i; return (E) elementData[lastRet = i]; } //设置元素值 public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.set(lastRet, e); } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } //增加元素 public void add(E e) { checkForComodification(); try { int i = cursor; ArrayList.this.add(i, e); cursor = i + 1; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } }
LinkedList的以双向链表作为数据的组织方式,其内部迭代器的实现和ArrayList的类似,只是访问元素要遍历。
从上面的实现可以看出:
1 我们使用的时候,虽然不知道内部是如何存储的,但我们还是很方便的可以操作容器类的元素,如果内部数组组织方式变了,只要提供正确的迭代器,我们程序不需要修改。
2 增加一种新的迭代器也很方便,不需要对容器类进行修改,内部类的方式只是提供了实现方便,迭代器的实现完全可以独立出来。
相关文章推荐
- java容器学习,HashMap(jdk1.8)
- java并发包学习系列:jdk并发容器(草稿)
- 《Java高并发程序设计》学习 --3.3 JDK的并发容器
- JDK容器学习之TreeMap (二) : 使用说明
- java学习之旅59--模拟ArrayList容器的底层实现_JDK源码分析ArrayList
- JDK容器学习之LinkedHashMap(一):底层存储结构分析
- JDK容器学习之LinkedHashMap(二):迭代遍历的实现方式
- 【Java高并发学习】Fork/Join框架、以及JDK中的高并发容器
- JDK容器学习之Map : HashMap,TreeMap,LinkedHashMap对比
- JDK容器学习之CopyOnWriteArrayList:线程安全保障机制
- JDK容器学习之TreeMap (一) : 底层数据结构
- JDK容器学习之HashMap (二) : 读写逻辑详解
- 学习《spring 3.x企业应用开发实战》之Spring容器高级主题
- 菜鸟Java学习笔记02--配置JDK环境变量的目的和HelloJava程序
- Spring学习总结(6)——Spring之核心容器bean
- 01--JDK学习随记
- STL学习笔记-容器
- c++primer阅读笔记之关联容器学习
- Java JDK 5.0学习笔记(二维数组)
- 设计模式学习笔记十六:迭代器模式