通过ArrayList迭代器使用进行JDK源码分析学习迭代器
2017-03-11 18:13
701 查看
JDK源码在学习过程中也经常跟中查阅,但是时间久了并每天接触的东西比较多,导致健忘,最近打算强化一下对迭代器的认识
首先看一个迭代器使用Demo,然后由此展开:
首先我们先查看一下Iterator<Integer> it = list.iterator();执行过程,看看迭代器倒是如何构建出来的!!!
调用的方法是:java.util.ArrayList.iterator(),源码如下:
接下来看看next方法:
首先会检查在便利过程中集合是否发生修改,发生修改的话直接抛出异常:
next最底层实现是直接操作的ArrayList的底层存储数组。
检查是否发生修改,如果使用迭代器进行遍历的话就用remove删除元素,但是此时使用list的remove的话就会异常:Exception in thread "main" java.util.ConcurrentModificationException
发生异常 Exception in thread "main" java.util.ConcurrentModificationException原因:
在使用迭代器删除时候会执行expectedModCount = modCount;。保证了expectedModCount 和modCount是相等的,但是如果直接使用list.remove的话这时expectedModCount 和modCount是不相等的所以抛异常。
异常例子代码:
接下来分析迭代器的设计,在JDK中有两个迭代器接口,按字面意思两个接口可以翻译为:
迭代者:
可以迭代的:
接下来看看Iterable的继承结构:
然而ArrayList(以ArrayList为例)恰好通过实现List接口间接实现了Collection接口,而Collection接口直接实现了Iterable接口:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
所以ArrayList中要实现Iterator<T> iterator()方法,而 iterator()方法返回值是Iterator<E>,由于每种集合有自己的特点,所以要需要根据自己实际情况实现自己的迭代者,由于迭代器都是操作集合的底层,所以不允许直接new迭代器,因此一般都把迭代器作为私有内部类通过共有方法把迭代器功能暴露出去(可以说是代理模式),ArrayList迭代者代码:
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;
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();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
拓展:集合除了根据自己特点实现自己特殊的Iterator之后外,还可以实现功能强大的Iterator,例如ArrayList还有ListItr迭代者,可以调用java.util.ArrayList.SubList.listIterator(int)方法返回ListItr迭代器,它是一个双向的迭代器,使用代码如下:
package com.daxin;
import java.util.ArrayList;
import java.util.ListIterator;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
list.add(i);
}
ListIterator<Integer> doubleIts = list.listIterator();
while (doubleIts.hasNext()) {
System.out.println(doubleIts.next());
}
System.out.println("------------------------------------");
while (doubleIts.hasPrevious()) {
System.out.println(doubleIts.previous());
}
}
}
简单分析:
通过翻阅ListItr源码可以发现ListItr继承结构如下:
private class ListItr extends Itr implements ListIterator<E>
所以ListItr只需要实现向前迭代的功能即可,向后迭代的功能直接使用Itr的即可。向前迭代功能和向后迭代实现原理一样。源码如下:
@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();
}
}
其他集合迭代器实现原理几乎一致,此处不再分析。
首先看一个迭代器使用Demo,然后由此展开:
package com.daxin; import java.util.ArrayList; import java.util.Iterator; public class Main { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); for (int i = 1; i <= 5; i++) { list.add(i); } Iterator<Integer> it = list.iterator();//生成迭代器 while (it.hasNext()) { System.out.println(it.next()); } } }
首先我们先查看一下Iterator<Integer> it = list.iterator();执行过程,看看迭代器倒是如何构建出来的!!!
调用的方法是:java.util.ArrayList.iterator(),源码如下:
/** * Returns an iterator over the elements in this list in proper sequence. * * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * * @return an iterator over the elements in this list in proper sequence */ public Iterator<E> iterator() { return new Itr(); }此处只new了一个java.util.ArrayList.Itr,可想而知Itr是ArrayList的一个内部类
/** * An optimized version of AbstractList.Itr */ 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 //上一次返回的值,例如:本次返回的元素序号是3,则此时lastRet=2 int expectedModCount = modCount;//ArrayList的大小 //判断当前是否下一个元素 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(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
接下来看看next方法:
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]; }
首先会检查在便利过程中集合是否发生修改,发生修改的话直接抛出异常:
next最底层实现是直接操作的ArrayList的底层存储数组。
public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData;//获取ArrayList数据存储的数组 if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i];//数组返回 }
检查是否发生修改,如果使用迭代器进行遍历的话就用remove删除元素,但是此时使用list的remove的话就会异常:Exception in thread "main" java.util.ConcurrentModificationException
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
发生异常 Exception in thread "main" java.util.ConcurrentModificationException原因:
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(); } }
在使用迭代器删除时候会执行expectedModCount = modCount;。保证了expectedModCount 和modCount是相等的,但是如果直接使用list.remove的话这时expectedModCount 和modCount是不相等的所以抛异常。
异常例子代码:
package com.daxin; import java.util.ArrayList; import java.util.Iterator; public class Main1 { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); for (int i = 1; i <= 5; i++) { list.add(i); } Iterator<Integer> it = list.iterator(); while (it.hasNext()) { System.out.println(it.next()); list.remove(2); } } }
接下来分析迭代器的设计,在JDK中有两个迭代器接口,按字面意思两个接口可以翻译为:
迭代者:
public interface Iterator<E> { boolean hasNext(); E next(); void remove(); }
可以迭代的:
package java.lang; import java.util.Iterator; /** * Implementing this interface allows an object to be the target of * the "foreach" statement. * * @param <T> the type of elements returned by the iterator * * @since 1.5 */ public interface Iterable<T> { /** * Returns an iterator over a set of elements of type T. * * @return an Iterator. */ Iterator<T> iterator(); }
接下来看看Iterable的继承结构:
然而ArrayList(以ArrayList为例)恰好通过实现List接口间接实现了Collection接口,而Collection接口直接实现了Iterable接口:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
所以ArrayList中要实现Iterator<T> iterator()方法,而 iterator()方法返回值是Iterator<E>,由于每种集合有自己的特点,所以要需要根据自己实际情况实现自己的迭代者,由于迭代器都是操作集合的底层,所以不允许直接new迭代器,因此一般都把迭代器作为私有内部类通过共有方法把迭代器功能暴露出去(可以说是代理模式),ArrayList迭代者代码:
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;
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();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
拓展:集合除了根据自己特点实现自己特殊的Iterator之后外,还可以实现功能强大的Iterator,例如ArrayList还有ListItr迭代者,可以调用java.util.ArrayList.SubList.listIterator(int)方法返回ListItr迭代器,它是一个双向的迭代器,使用代码如下:
package com.daxin;
import java.util.ArrayList;
import java.util.ListIterator;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
list.add(i);
}
ListIterator<Integer> doubleIts = list.listIterator();
while (doubleIts.hasNext()) {
System.out.println(doubleIts.next());
}
System.out.println("------------------------------------");
while (doubleIts.hasPrevious()) {
System.out.println(doubleIts.previous());
}
}
}
简单分析:
通过翻阅ListItr源码可以发现ListItr继承结构如下:
private class ListItr extends Itr implements ListIterator<E>
所以ListItr只需要实现向前迭代的功能即可,向后迭代的功能直接使用Itr的即可。向前迭代功能和向后迭代实现原理一样。源码如下:
@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();
}
}
其他集合迭代器实现原理几乎一致,此处不再分析。
相关文章推荐
- JDK源码学习(4)-HashMap的遍历方式,两种迭代器源码分析
- java学习之旅56--数组_StringBuilder和StringBuffer的使用_常用方法_方法链的实现_JDK源码分析
- java学习之旅57、58--数组_StringBuilder和StringBuffer的使用_JDK源码分析内部机制、常用方法补充_常见面试题答法
- java学习之旅65--常用类_Date类的使用_JDk源码分析
- AIDL使用学习(三):源码深入分析
- 开源中国源码学习UI篇(一)之FragmentTabHost的使用分析
- MyBatis Mapper 接口如何通过JDK动态代理来包装SqlSession 源码分析
- 使用JDK自带的VisualVM进行Java程序的性能分析
- 通过JDK源码学习InputStream详解
- phoenix 如何优化成使用索引进行查询源码分析
- JDK源码学习之HashMap (一) : 底层存储结构分析
- motan源码分析二:使用spi机制进行类加载
- Elasticsearch源码分析之一——使用Guice进行依赖注入与模块化系统
- 【JDK源码学习】ResourceBundle使用详解
- 前面学习通过方法对代码进行改进,为什么要给方法使用静态呢?
- 一步步学习 Mybatis:缓存的使用及源码分析
- java核心基础--jdk源码分析学习--Hashtable
- iOS开发工具-如何使用网络封包分析工具Charles,通过配置proxy对http、https、tcp、udp 等协议的请求响应过程交互信息进行分析、判断、解决我们移动开发中的遇到的各种实际问题。