读读源码-ArrayList究竟是怎么实现增强for循环的?
以我的认知来说,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 return int lastRet = -1; // index of last element returned; -1 if no such int 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 @Override public Iterator iterator() { return new Itr(); } class Itr implements Iterator<String> { private final int max = 3; private int cursor = 0; @Override public boolean hasNext() { return cursor < max; } @Override public 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(); }; } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2024-02-10 pyspark初步了解
2024-02-10 RDD入门了解