概述
循环作为程序中经常使用的语句,在java5之后推出了新的for/in(foreach)循环方式以方便程序员编写(阅读)代码。这种方式并不是新的语法,只是语法糖。即编写的foreach循环的代码并不是直接转成字节码,而是由编译器先转成对应的语法,然后再转成字节码,可以理解成是编译器对一些语法的封装提供的另一种方便阅读编写功能代码的实现方式。java中提供的foreach语法糖其底层实现方式主要有两种:对于集合类或实现迭代器的集合使用迭代器的遍历方式,对于数组集合使用数组的遍历方法。
迭代器遍历模式
对于实现Iterator接口的集合,使用foreach实现循环功能的代码会被编译器转换成使用迭代器遍历集合的代码,然后再转成字节码。例如以下的程序,使用foreach循环遍历ArrayList集合,使用javac TestForEach.java生成字节码后,再使用javap -verbose TestForEach进行反编译,从反编译的结果来看,可以看出其底层是用迭代器模式进行遍历的。
import java.util.ArrayList;
import java.util.List;
public class TestForEach
{
public static void main(String args[])
{
List nums = new ArrayList<>();
nums.add(11);
nums.add(22);
nums.add(33);
for (Integer num : nums)
{
System.out.println(num);
}
}
}
反编译结果如下,从中可以看出,在106118这十几行中是对集合进行遍历输出,在106行先使用`List.iterator()`接口生成迭代器,然后在109118中不断使用Iterator.hasNext()判断是否有下个元素,有则使用Iterator.next()接口获取下个元素并进行输出。
Classfile /C:/Users/zhchun/Desktop/TestForEach.class
Last modified 2018-7-22; size 842 bytes
MD5 checksum 45751115d8755b894835c52451125338
Compiled from "TestForEach.java"
public class TestForEach
SourceFile: "TestForEach.java"
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #13.#25 // java/lang/Object."":()V
#2 = Class #26 // java/util/ArrayList
#3 = Methodref #2.#25 // java/util/ArrayList."":()V
#4 = Methodref #9.#27 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
#5 = InterfaceMethodref #28.#29 // java/util/List.add:(Ljava/lang/Object;)Z
#6 = InterfaceMethodref #28.#30 // java/util/List.iterator:()Ljava/util/Iterator;
#7 = InterfaceMethodref #31.#32 // java/util/Iterator.hasNext:()Z
#8 = InterfaceMethodref #31.#33 // java/util/Iterator.next:()Ljava/lang/Object;
#9 = Class #34 // java/lang/Integer
#10 = Fieldref #35.#36 // java/lang/System.out:Ljava/io/PrintStream;
#11 = Methodref #37.#38 // java/io/PrintStream.println:(Ljava/lang/Object;)V
#12 = Class #39 // TestForEach
#13 = Class #40 // java/lang/Object
#14 = Utf8
#15 = Utf8 ()V
#16 = Utf8 Code
#17 = Utf8 LineNumberTable
#18 = Utf8 main
#19 = Utf8 ([Ljava/lang/String;)V
#20 = Utf8 StackMapTable
#21 = Class #41 // java/util/List
#22 = Class #42 // java/util/Iterator
#23 = Utf8 SourceFile
#24 = Utf8 TestForEach.java
#25 = NameAndType #14:#15 // "":()V
#26 = Utf8 java/util/ArrayList
#27 = NameAndType #43:#44 // valueOf:(I)Ljava/lang/Integer;
#28 = Class #41 // java/util/List
#29 = NameAndType #45:#46 // add:(Ljava/lang/Object;)Z
#30 = NameAndType #47:#48 // iterator:()Ljava/util/Iterator;
#31 = Class #42 // java/util/Iterator
#32 = NameAndType #49:#50 // hasNext:()Z
#33 = NameAndType #51:#52 // next:()Ljava/lang/Object;
#34 = Utf8 java/lang/Integer
#35 = Class #53 // java/lang/System
#36 = NameAndType #54:#55 // out:Ljava/io/PrintStream;
#37 = Class #56 // java/io/PrintStream