Java for、foreach 循环底层实现原理,以及如何判断集合支持 foreach 循环

您所在的位置:网站首页 java嵌套循环的运行原理 Java for、foreach 循环底层实现原理,以及如何判断集合支持 foreach 循环

Java for、foreach 循环底层实现原理,以及如何判断集合支持 foreach 循环

#Java for、foreach 循环底层实现原理,以及如何判断集合支持 foreach 循环| 来源: 网络整理| 查看: 265

专栏原创出处:github-源笔记文件 ,github-源码 ,欢迎 Star,转载请附上原文出处链接和本声明。

Java 核心知识专栏系列笔记,系统性学习可访问个人复盘笔记-技术博客 Java 核心知识

一、前言

本节内容主要研究 for、foreach 循环的底层实现原理,再比较两种实现方式的性能。最后通过 RandomAccess 接口说明 JDK 让我们怎么去识别集合是否支持随机访问。

随机访问表示,像数组那样,随便给定一个下标我们就可以访问内存的数据。而链式结构的存储只能顺序遍历各个链表节点访问。

二、for 循环底层实现

for 循环是对数值型数据出栈、改变值、比较的过程。

public void foriMethod() { for (int i = 0; i for (String s : list) { } } // 等价于 for (Iterator i=list.iterator(); i.hasNext(); ) i.next(); ———— 转为字节码,部分关键字节码如下: 0 aload_1 // 将第二个引用类型本地变量 (list) 推送至栈顶 1 invokeinterface #2 // 调用 iterator 方法 count 1 6 astore_2 // 将栈顶引用型数值存入第三个本地变量 7 aload_2 // 将第三个引用类型本地变量推送至栈顶 8 invokeinterface #3 // 调用 Iterator.hasNext count 1 13 ifeq 29 (+16) // 当栈顶 int 型数值等于 0 时跳转到 29 code 16 aload_2 // 将第三个引用类型本地变量推送至栈顶 17 invokeinterface #4 // 调用 Iterator.hasNext 方法返回当前取值对象 count 1 22 checkcast #5 // 强转为 25 astore_3 // 将栈顶引用型数值存入第四个本地变量 26 goto 7 (-19) // 继续循环 29 return 四、foreach 与 for 性能比较

先下结论:

尽量使用 for 循环,开销比 foreach 低。

对于 (int i = 0; i < list.size(); i++) ,长度尽量定义为变量,减少每次计算消耗。

—————————————————————————— foreach 生成字节码 ——————————————————————— for (String s : list) {} 0 aload_1 1 invokeinterface #2 count 1 6 astore_2 7 aload_2 8 invokeinterface #3 count 1 13 ifeq 29 (+16) 16 aload_2 17 invokeinterface #4 count 1 22 checkcast #5 25 astore_3 26 goto 7 (-19) —————————————————————————— for 生成字节码 ————————————————————————— for (int i = 0; i return new Itr(); // 每次调用实时创建返回 } // ArrayList.Itr 类中的 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]; } 如果我们用 for 时,只需要根据下标值,取对应的数据即可 public E get(int index) { Objects.checkIndex(index, size); return elementData(index); } 五、RandomAccess 接口让我们尽量使用 for 循环 RandomAccess 接口是干什么的? public interface RandomAccess { }

我们可以看到这个接口没有任何实现,它仅仅起一个标识的作用,标识这个集合是否支持随机访问。类似于 Serializable, Cloneable。

RandomAccess 接口有什么用?

举个例子:

List 接口有 ArrayList、LinkedList 两个实现。但是 LinkedList 底层是链表实现不支持随机访问,所以无法使用 for 循环,只能使用 foreach 循环遍历了。

public void randomAccess(List list) { if (list instanceof RandomAccess) { for (int i = 0; i for (T t : list) { System.out.println(t); } } }

现在我们知道为什么 Set 接口没有实现 RandomAccess 接口了。这也是为什么 Set 不能通过下标取值的原因之一。

Set 底层一般通过 Map 集合的 Key 实现的。我们知道 Map 作为一个哈希表底层使用链表节点存储。因此不支持随机访问。这也是为什么 Set 没有 get(int index) 方法的根本原因。

专栏更多文章笔记

Java 核心知识-专栏文章目录汇总

Java 并发编程-专栏文章目录汇总

Java JVM(JDK13)-专栏文章目录汇总



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3