以我的认知来说,java中的ArrayList实现List,List又是继承Collection,往后就不太清楚了。
今天看源码的时候发现Collection继承了Iterable,Iterable接口的作用是允许对象称为for-each loop语句的目标。
因此如果想了解ArrayList如何实现循环,我们必须先从Iterable看起
1.集合之上的接口Iterable
在Iterable中有一个Iterator方法,其他方法,比如foreach都是有default,暂时先不用看
public interface Iterable<T> {Iterator<T> iterator();default void forEach(Consumer<? super T> action) {Objects.requireNonNull(action);for (T t : this) {action.accept(t);}}default Spliterator<T> spliterator() {return Spliterators.spliteratorUnknownSize(iterator(), 0);} }
在Iterator接口中也有两个需要实现的方法
boolean hasNext()和T next()通过名字我们就知道这两个方法是检测当前循环里有没有下一个数据以及下一个数据的返回。
2.增强for语句的真面貌
//正常使用的增强for方法public static void enhanceFor(ArrayList<String> list){for (String s : list) {System.out.println(s);}}
//编译后的class文件 public static void enhanceFor(ArrayList<String> list) {Iterator var1 = list.iterator();while(var1.hasNext()) {String s = (String)var1.next();System.out.println(s);}}
可以看到,增强的for方法实际就是使用的迭代器内的方法实现的循环遍历
3.ArrayList中的Iterable
那么实际在ArrayList中,是如何实现的Iterable与Iterator呢?、
Iterator中只写了返回一个对象,通过原接口我们知道这个对象就是Iterator
public Iterator<E> iterator() {return new Itr();}
private class Itr implements Iterator<E> {int cursor; // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;Itr() {}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];}}
这里我们只看hasNext和next方法
hasNext中,只要游标cursor不等于size就返回true,也就是说明后面还有数据
next方法中,首先是checkForComodification方法,可以看到是在检测modCount和expectedModCount是否相等
final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}
通过解释我们知道,在正常的循环的时候modCount和expectedModCount是应该被指定好且相同的、
但是如果我们在循环中改变了循环体,那会导致两者参数不一致进而出现迭代产生错误结果,为此抛出了这段异常。
后续就是检测越界问题,没问题的话就给游标加一保证迭代并将集合中获得的元素返回。
4.让自定义类也能实现for循环
读过上述源码后,我们就知道如何给一个自定义类实现增强for循环了
@Data @ToString public class User implements Iterable {String name;Integer age;Boolean sex;@NotNull@Overridepublic Iterator iterator() {return new Itr();}class Itr implements Iterator<String> {private final int max = 3;private int cursor = 0;@Overridepublic boolean hasNext() {return cursor < max;}@Overridepublic String next() {return switch (cursor++) {case 0 -> name != null ? name : "null";case 1 -> age != null ? age.toString() : "null";case 2 -> sex != null ? sex.toString() : "null";default -> throw new NoSuchElementException();};}} }