您的位置:首页 > 编程语言 > Java开发

通过ArrayList迭代器使用进行JDK源码分析学习迭代器

2017-03-11 18:13 701 查看
JDK源码在学习过程中也经常跟中查阅,但是时间久了并每天接触的东西比较多,导致健忘,最近打算强化一下对迭代器的认识

首先看一个迭代器使用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();
}
}

其他集合迭代器实现原理几乎一致,此处不再分析。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: