java加强for轮回的道理验证
在java里,我们是怎么写for轮回的代码呢。一般都是用这两种写法:
第一种:最传统的for轮回写法,for(代码段a;代码段b;代码段c),个中代码段a是初次进入for轮回时执行的代码,代码段b是一个boolean的表达式,true则继承执行for轮回内容,false则遏制for轮回,代码段c则是在for轮回内部执行完后执行。
第二种:针对荟萃的遍历,for(范例 单个工具:荟萃工具)。第二种等于加强for轮回。
本文的目标就是讲授加强for轮回的道理。先看我的测试用例:
jdk版本:1.7.0_51
java 用例代码:
package com.onlyou.olyfinance.supply.web; import java.util.Arrays; import java.util.Iterator; import java.util.List; /** * 加强for轮回编译测试 * Created by cd_huang on 2017/4/14. */ public class ForeachTest { public static void superForeachTestArray(){ String[] args =new String[]{"1","2"}; for(String s:args) { System.out.println(s); } } public static void foreachTestArray(){ String[] args =new String[]{"1","2"}; String[] args2 = args; int len = args.length; for(int i = 0; i < len; ++i) { String s= args2[i]; System.out.println(s); } } public static void superForeachTestIterator(){ List<String> list = Arrays.asList(new String[]{"1","2"}); for(String s:list) { System.out.println(s); } } public static void foreachTestIterator(){ List<String> list = Arrays.asList(new String[]{"1","2"}); Iterator it = list.iterator(); while(it.hasNext()) { String s = (String)it.next(); System.out.println(s); } } }
呼吁行输入:C:\Users\hcd>javac c:\ForeachTest.java
生成StringTest.class文件。
呼吁行输入:C:\Users\hcd>javap -v c:\ForeachTest.class
生成java编译后的字节码指令。
Classfile /c:/ForeachTest.class Last modified 2017-4-14; size 1307 bytes MD5 checksum 5296942b41a468b4fa1f88e3123db02f Compiled from "ForeachTest.java" public class com.onlyou.olyfinance.supply.web.ForeachTest SourceFile: "ForeachTest.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #13.#28 // java/lang/Object."<init>":()V #2 = Class #29 // java/lang/String #3 = String #30 // 1 #4 = String #31 // 2 #5 = Fieldref #32.#33 // java/lang/System.out:Ljava/io/PrintStream; #6 = Methodref #34.#35 // java/io/PrintStream.println:(Ljava/lang/String;)V #7 = Methodref #36.#37 // java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List; #8 = InterfaceMethodref #38.#39 // java/util/List.iterator:()Ljava/util/Iterator; #9 = InterfaceMethodref #40.#41 // java/util/Iterator.hasNext:()Z #10 = InterfaceMethodref #40.#42 // java/util/Iterator.next:()Ljava/lang/Object; #11 = InterfaceMethodref #38.#39 // java/util/List.iterator:()Ljava/util/Iterator; #12 = Class #43 // com/onlyou/olyfinance/supply/web/ForeachTest #13 = Class #44 // java/lang/Object #14 = Utf8 <init> #15 = Utf8 ()V #16 = Utf8 Code #17 = Utf8 LineNumberTable #18 = Utf8 superForeachTestArray #19 = Utf8 StackMapTable #20 = Class #45 // "[Ljava/lang/String;" #21 = Utf8 foreachTestArray #22 = Utf8 superForeachTestIterator #23 = Class #46 // java/util/List #24 = Class #47 // java/util/Iterator #25 = Utf8 foreachTestIterator #26 = Utf8 SourceFile #27 = Utf8 ForeachTest.java #28 = NameAndType #14:#15 // "<init>":()V #29 = Utf8 java/lang/String #30 = Utf8 1 #31 = Utf8 2 #32 = Class #48 // java/lang/System #33 = NameAndType #49:#50 // out:Ljava/io/PrintStream; #34 = Class #51 // java/io/PrintStream #35 = NameAndType #52:#53 // println:(Ljava/lang/String;)V #36 = Class #54 // java/util/Arrays #37 = NameAndType #55:#56 // asList:([Ljava/lang/Object;)Ljava/util/List; #38 = Class #46 // java/util/List #39 = NameAndType #57:#58 // iterator:()Ljava/util/Iterator; #40 = Class #47 // java/util/Iterator #41 = NameAndType #59:#60 // hasNext:()Z #42 = NameAndType #61:#62 // next:()Ljava/lang/Object; #43 = Utf8 com/onlyou/olyfinance/supply/web/ForeachTest #44 = Utf8 java/lang/Object #45 = Utf8 [Ljava/lang/String; #46 = Utf8 java/util/List #47 = Utf8 java/util/Iterator #48 = Utf8 java/lang/System #49 = Utf8 out #50 = Utf8 Ljava/io/PrintStream; #51 = Utf8 java/io/PrintStream #52 = Utf8 println #53 = Utf8 (Ljava/lang/String;)V #54 = Utf8 java/util/Arrays #55 = Utf8 asList #56 = Utf8 ([Ljava/lang/Object;)Ljava/util/List; #57 = Utf8 iterator #58 = Utf8 ()Ljava/util/Iterator; #59 = Utf8 hasNext #60 = Utf8 ()Z #61 = Utf8 next #62 = Utf8 ()Ljava/lang/Object; { public com.onlyou.olyfinance.supply.web.ForeachTest(); flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 11: 0 public static void superForeachTestArray(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=5, args_size=0 0: iconst_2 1: anewarray #2 // class java/lang/String 4: dup 5: iconst_0 6: ldc #3 // String 1 8: aastore 9: dup 10: iconst_1 11: ldc #4 // String 2 13: aastore 14: astore_0 15: aload_0 16: astore_1 17: aload_1 18: arraylength 19: istore_2 20: iconst_0 21: istore_3 22: iload_3 23: iload_2 24: if_icmpge 46 27: aload_1 28: iload_3 29: aaload 30: astore 4 32: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 35: aload 4 37: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 40: iinc 3, 1 43: goto 22 46: return LineNumberTable: line 14: 0 line 15: 15 line 16: 32 line 15: 40 line 18: 46 StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 22 locals = [ class "[Ljava/lang/String;", class "[Ljava/lang/String;", int, int ] stack = [] frame_type = 248 /* chop */ offset_delta = 23 public static void foreachTestArray(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=5, args_size=0 0: iconst_2 1: anewarray #2 // class java/lang/String 4: dup 5: iconst_0 6: ldc #3 // String 1 8: aastore 9: dup 10: iconst_1 11: ldc #4 // String 2 13: aastore 14: astore_0 15: aload_0 16: astore_1 17: aload_0 18: arraylength 19: istore_2 20: iconst_0 21: istore_3 22: iload_3 23: iload_2 24: if_icmpge 46 27: aload_1 28: iload_3 29: aaload 30: astore 4 32: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 35: aload 4 37: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 40: iinc 3, 1 43: goto 22 46: return LineNumberTable: line 21: 0 line 22: 15 line 23: 17 line 24: 20 line 25: 27 line 26: 32 line 24: 40 line 28: 46 StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 22 locals = [ class "[Ljava/lang/String;", class "[Ljava/lang/String;", int, int ] stack = [] frame_type = 250 /* chop */ offset_delta = 23 public static void superForeachTestIterator(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=3, args_size=0 0: iconst_2 1: anewarray #2 // class java/lang/String 4: dup 5: iconst_0 6: ldc #3 // String 1 8: aastore 9: dup 10: iconst_1 11: ldc #4 // String 2 13: aastore 14: invokestatic #7 // Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List; 17: astore_0 18: aload_0 19: invokeinterface #8, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 24: astore_1 25: aload_1 26: invokeinterface #9, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 31: ifeq 54 34: aload_1 35: invokeinterface #10, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 40: checkcast #2 // class java/lang/String 43: astore_2 44: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 47: aload_2 48: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 51: goto 25 54: return LineNumberTable: line 31: 0 line 32: 18 line 33: 44 line 34: 51 line 35: 54 StackMapTable: number_of_entries = 2 frame_type = 253 /* append */ offset_delta = 25 locals = [ class java/util/List, class java/util/Iterator ] frame_type = 250 /* chop */ offset_delta = 28 public static void foreachTestIterator(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=3, args_size=0 0: iconst_2 1: anewarray #2 // class java/lang/String 4: dup 5: iconst_0 6: ldc #3 // String 1 8: aastore 9: dup 10: iconst_1 11: ldc #4 // String 2 13: aastore 14: invokestatic #7 // Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List; 17: astore_0 18: aload_0 19: invokeinterface #11, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 24: astore_1 25: aload_1 26: invokeinterface #9, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 31: ifeq 54 34: aload_1 35: invokeinterface #10, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 40: checkcast #2 // class java/lang/String 43: astore_2 44: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 47: aload_2 48: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 51: goto 25 54: return LineNumberTable: line 38: 0 line 39: 18 line 40: 25 line 41: 34 line 42: 44 line 43: 51 line 44: 54 StackMapTable: number_of_entries = 2 frame_type = 253 /* append */ offset_delta = 25 locals = [ class java/util/List, class java/util/Iterator ] frame_type = 28 /* same */ }
#p#分页标题#e#
上面的是java代码编译事后的二进制指令。假如对这些指令是什么意思有乐趣的可以看这篇博客:http://www.blogjava.net/DLevin/archive/2011/09/13/358497.html。不外单单看这个必定是不足的。需要对java的运行时内存模子有必然的相识,大白栈帧,操纵数栈,局部变量表,常量池这些对象的观念,才气领略在执行这些指令时,对应的对象里会发生什么变革。虽然,要领略我说的加强for轮回道理,并不需要看懂这些指令。当真调查上面的二进制指令,superForeachTestArray()要领编译后的指令,即第86行到121行,和foreachTestArray() 要领编译后的指令,即第137行到172行,两个要领编译后的指令是一样的。
#p#分页标题#e#
superForeachTestIterator()要领编译后的指令,即第191行到222行,和foreachTestIterator() 要领编译后的指令,即第237行到268行,两个要领编译后的指令是一样的。
这说明什么问题?说明白加强for轮回是一个编译前的观念,在编译后编译器会对代码举办优化。有两种工具支持加强for轮回:一种是数组,编译器对数组的优化只是写法上的优化,即superForeachTestArray()要领内的加强for轮回在编译后会酿成foreachTestArray() 要领里for轮回的代码。一种是实现了Iterable接口的工具,对付这种,其实质是拿到工具的迭代器举办遍历,即superForeachTestIterator()要领内的加强for轮回在编译后会酿成foreachTestIterator() 要领内的迭代器遍历。迭代器遍历的长处是安详,且它是对遍历的一种抽象,有种解耦的意味在内里。