本文共 9037 字,大约阅读时间需要 30 分钟。
for-each循环是jdk1.5引入的新的语法功能。并不是所有东西都可以使用这个循环的。可以看下Iterable接口的注释,它说明了除了数组外,其他类想要使用for-each循环必须实现这个接口。这一点表明除了数组外的for-each可能底层是由迭代器实现的。
Iterable接口在1.8之前只有一个方法,Iterator<T> iterator(),此方法返回一个迭代器。由于更早出现的Collection接口中早就有了这个同样的方法,所以只需要让Collection接口继承Iterable接口,基于Collection的集合类就可以不做任何更改就使用for-each循环。
package iter;public class TestArray { public static void main(String[] args) { //String[] a = {"a", "b", "c"}; long[] a = {2L, 3L, 5L}; for (long i : a) { System.err.println(i); } }}
package iter;public class TestArrayFor { public static void main(String[] args) { //String[] a = {"a", "b", "c"}; long[] a = {2L, 3L, 5L}; for (int i = 0, len = a.length; i < len; i++) { System.err.println(a[i]); } }}TestArray使用for-each,TestArrayFor使用传统for循环,使用long数组是为了字节码中好区分int/long。
Compiled from "TestArray.java"public class iter.TestArray { public iter.TestArray(); Code: 0: aload_0 1: invokespecial #8 // Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: iconst_3 1: newarray long 3: dup 4: iconst_0 5: ldc2_w #16 // long 2l 8: lastore 9: dup 10: iconst_1 11: ldc2_w #18 // long 3l 14: lastore 15: dup 16: iconst_2 17: ldc2_w #20 // long 5l 20: lastore 21: astore_1 /* 0-21行,创建long数组a,并保存在线程的当前栈帧的局部变量表的第1格*/ 22: aload_1 /* 读取保存在线程的当前栈帧的局部变量表的第1格的对象的引用,就是读取数组a */ 23: dup /* 把a的引用复制一遍并且再放到栈顶 */ 24: astore 6 /* 把栈顶的数存在线程的当前栈帧的局部变量表的第6格,就是生成a的一个值复制品b并存储起来,暂时不知道为什么这里要复制一次,后面的数组都还是用a表示 */ 26: arraylength /* 获取数组长度a.length */ 27: istore 5 /* 把数组长度存储在线程的当前栈帧的局部变量表的第5格,22-27隐式执行了int len = a.length */ 29: iconst_0 /* 读取数字0(这个就是普通的0)到栈中 */ 30: istore 4 /* 把数字0放在线程的当前栈帧的局部变量表的第4格,29-30隐式执行了int i = 0 */ 32: goto 51 /* 无条件跳转到51那个地方,开始循环的代码 */ 35: aload 6 /* 读取数组a */ 37: iload 4 /* 读取i */ 39: laload /* 读取a[i] */ 40: lstore_2 /* 把a[i]存在线程的当前栈帧的局部变量表的第2格 */ 41: getstatic #22 // Field java/lang/System.err:Ljava/io/PrintStream; /* 获取类的static属性,就是System.err */ 44: lload_2 /* 读取存在线程的当前栈帧的局部变量表的第2格的数据,就是读取a[i] */ 45: invokevirtual #28 // Method java/io/PrintStream.println:(J)V /* 执行虚拟机方法,30-36就是执行System.err.println(a[i]) */ 48: iinc 4, 1 /* 将第4格的数字加1,就是执行i++ */ 51: iload 4 /* 读取i */ 53: iload 5 /* 读取a.length */ 55: if_icmplt 35 /* 如果i < len,跳到标记35的那个地方,不满足就往下 */ 58: return}
Compiled from "TestArrayFor.java"public class iter.TestArrayFor { public iter.TestArrayFor(); Code: 0: aload_0 1: invokespecial #8 // Method java/lang/Object."本人对照下字节码指令表,简单翻译了以下,都写在上面,还算是比较清楚。/**/中的就是本人的注释,//开头的是字节码自带的信息,这些信息不能完全算是注释吧,可以算是对字节码中出现的常量的一种直白翻译,让你看得懂这些常量代表什么。":()V 4: return public static void main(java.lang.String[]); Code: 0: iconst_3 1: newarray long 3: dup 4: iconst_0 5: ldc2_w #16 // long 2l 8: lastore 9: dup 10: iconst_1 11: ldc2_w #18 // long 3l 14: lastore 15: dup 16: iconst_2 17: ldc2_w #20 // long 5l 20: lastore 21: astore_1 /* 0-21行,创建long数组a,并保存在线程的当前栈帧的局部变量表的第1格*/ 22: iconst_0 /* 读取数字0(这个就是普通的0)到栈中 */ 23: istore_2 /* 将栈顶的数字0保存在第二个,22-23就是执行int i = 0; */ 24: aload_1 /* 读取保存在线程的当前栈帧的局部变量表的第1格的对象的引用,就是读取数组a */ 25: arraylength /* 获取数组长度a.length */ 26: istore_3 /* 把数组长度保存在线程的当前栈帧的局部变量表的第3格,24-26就是执行int len = a.length */ 27: goto 42 /* 无条件跳到标记42的那个地方,开始循环的代码 */ 30: getstatic #22 // Field java/lang/System.err:Ljava/io/PrintStream; /* 获取类的static属性,就是System.err */ 33: aload_1 /* 读取数组a */ 34: iload_2 /* 读取i */ 35: laload /* 读取a[i] */ 36: invokevirtual #28 // Method java/io/PrintStream.println:(J)V /* 执行虚拟机方法,30-36就是执行System.err.println(a[i]) */ 39: iinc 2, 1 /* 将第2格的数字加1,就是执行i++ */ 42: iload_2 /* 读取i */ 43: iload_3 /* 读取len */ 44: if_icmplt 30 /* 如果i < len,跳到标记30的那个地方,不满足就往下 */ 47: return}
package iter;import java.util.ArrayList;import java.util.List;public class TestFor { public static void main(String[] args) { ListlistA = new ArrayList (); for(String str : listA) { System.err.println(str); } }}
package iter;import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class TestIter { public static void main(String[] args) { ListlistA = new ArrayList (); for (Iterator iter = listA.iterator(); iter.hasNext();) { String s = iter.next(); System.err.println(s); } }}
Compiled from "TestFor.java"public class iter.TestFor { public iter.TestFor(); Code: 0: aload_0 1: invokespecial #8 // Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: new #16 // class java/util/ArrayList 3: dup 4: invokespecial #18 // Method java/util/ArrayList." ":()V 7: astore_1 8: aload_1 9: invokeinterface #19, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 14: astore_3 15: goto 35 18: aload_3 19: invokeinterface #25, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 24: checkcast #31 // class java/lang/String 27: astore_2 28: getstatic #33 // Field java/lang/System.err:Ljava/io/PrintStream; 31: aload_2 32: invokevirtual #39 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 35: aload_3 36: invokeinterface #45, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 41: ifne 18 44: return}
Compiled from "TestIter.java"public class iter.TestIter { public iter.TestIter(); Code: 0: aload_0 1: invokespecial #8 // Method java/lang/Object."这两段字节码中自带的注释很多,基本上看得懂,就不添加注释了。":()V 4: return public static void main(java.lang.String[]); Code: 0: new #16 // class java/util/ArrayList 3: dup 4: invokespecial #18 // Method java/util/ArrayList." ":()V 7: astore_1 8: aload_1 9: invokeinterface #19, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 14: astore_2 15: goto 35 18: aload_2 19: invokeinterface #25, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 24: checkcast #31 // class java/lang/String 27: astore_3 28: getstatic #33 // Field java/lang/System.err:Ljava/io/PrintStream; 31: aload_3 32: invokevirtual #39 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 35: aload_2 36: invokeinterface #45, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 41: ifne 18 44: return}
转载地址:http://qrcws.baihongyu.com/