在平时Java程序中,应用比较多的就是对Collection集合类的foreach遍历,foreach之所以能工作,是因为这些集合类都实现了Iterable接口,该接口中定义了Iterator迭代器的产生方法,并且foreach就是通过Iterable接口在序列中进行移动。
Iterable 接口 API
packagejava.lang; importjava.util.Iterator; publicinterfaceIterable { publicabstractIteratoriterator(); }
该接口中定义了产生Iterator迭代器的方法
packagejava.util; publicinterfaceIterator { publicabstractbooleanhasNext(); publicabstractObjectnext(); publicabstractvoidremove(); }
那么为什么实现了Iterable接口就支持foreach操作了呢?
我们写段foreach小程序看看字节码是怎么样的吧!
packagetest; importjava.util.List; publicclassTestForeach { List<Integer>integers; publicvoidtestForeach(){ for(Integeri : integers){ } } }
其中TestForeach方法的详细字节码如下
publicvoidtestForeach(); descriptor: ()Vflags: ACC_PUBLICCode: stack=1, locals=3, args_size=10: aload_01: getfield#2// Field integers:Ljava/util/List;4: invokeinterface#3, 1// InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;9: astore_110: aload_111: invokeinterface#4, 1// InterfaceMethod java/util/Iterator.hasNext:()Z16: ifeq3219: aload_120: invokeinterface#5, 1// InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;25: checkcast#6// class java/lang/Integer28: astore_229: goto1032: returnLineNumberTable: line11: 0line13: 29line14: 32LocalVariableTable: StartLengthSlotNameSignature2902iLjava/lang/Integer; 0330thisLtest/TestForeach; }
我们重点看红色部分,我来简单解释一下这段字节码的作用
0:加载this到操作栈
1:获取字段integers
4:调用integers的接口方法interator
9:将返回的迭代器赋给本地变量?(我们看到在最下面的本地变量区的Slot列,有0和2,但是没有1。事实上,1 就是编译器为我们生成的一个迭代器变量),这边就是给这个迭代器赋值
核心实现就是以上几行字节码,其余的部分就是和接下来的迭代器遍历有关了,有兴趣的朋友可以看看。