Fou循環經常用,可是在字節碼層它是怎樣執行的呢?出於興趣驅使,就有了這篇短文了!java
首先要分析字節碼就得先寫個類了,代碼以下:shell
public class ForTest{ public static void main(String[] args) { for (int i = 0; i < 10; ++i) { System.out.println(i); } } }
簡單的for循環打印10個數,那麼編譯以後就該獲得他的字節碼了,使用命令app
javap -v ForTest.class > ForTest.j
這裏用到 -v 參數,導出了整個class文件的詳情,若是隻是想簡單獲得字節碼,就只需換成 -c 參數就成了,這裏獲得的結果以下:
spa
Classfile /E:/Develop/JavaTest/ForTest.class Last modified 2015-1-2; size 437 bytes MD5 checksum 21aad18f3a51ffa226ad2f49d7c3f5e0 Compiled from "ForTest.java" public class ForTest SourceFile: "ForTest.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #5.#15 // java/lang/Object."<init>":()V #2 = Fieldref #16.#17 // java/lang/System.out:Ljava/io/PrintStream; #3 = Methodref #18.#19 // java/io/PrintStream.println:(I)V #4 = Class #20 // ForTest #5 = Class #21 // java/lang/Object #6 = Utf8 <init> #7 = Utf8 ()V #8 = Utf8 Code #9 = Utf8 LineNumberTable #10 = Utf8 main #11 = Utf8 ([Ljava/lang/String;)V #12 = Utf8 StackMapTable #13 = Utf8 SourceFile #14 = Utf8 ForTest.java #15 = NameAndType #6:#7 // "<init>":()V #16 = Class #22 // java/lang/System #17 = NameAndType #23:#24 // out:Ljava/io/PrintStream; #18 = Class #25 // java/io/PrintStream #19 = NameAndType #26:#27 // println:(I)V #20 = Utf8 ForTest #21 = Utf8 java/lang/Object #22 = Utf8 java/lang/System #23 = Utf8 out #24 = Utf8 Ljava/io/PrintStream; #25 = Utf8 java/io/PrintStream #26 = Utf8 println #27 = Utf8 (I)V { public ForTest(); 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 1: 0 public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: iconst_0 1: istore_1 2: iload_1 3: bipush 10 5: if_icmpge 21 8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 11: iload_1 12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 15: iinc 1, 1 18: goto 2 21: return LineNumberTable: line 3: 0 line 4: 8 line 3: 15 line 6: 21 StackMapTable: number_of_entries = 2 frame_type = 252 /* append */ offset_delta = 2 locals = [ int ] frame_type = 250 /* chop */ offset_delta = 18 }
其實重點仍是下面這段代碼,其餘內容只是方便理解和分析class文件:code
0: iconst_0 1: istore_1 2: iload_1 3: bipush 10 5: if_icmpge 21 8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 11: iload_1 12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 15: iinc 1, 1 18: goto 2 21: return
如今就分析分析For循環是怎麼執行的了ip
首先先初始化循環變量:ci
0: iconst_0 1: istore_1
這兩行代碼至關於 int i = 0 這句代碼(iconst_0 是數字 0,istore_1 就是表示局部變量1,這裏就是源碼裏的 i 了)get
而後判斷循環條件:源碼
2: iload_1 3: bipush 10 5: if_icmpge 21
這三行意思就是 i 是否小於 10 ,小於則繼續往下執行,不然就跳到 編號爲 21 的 return那裏也即跳出for循環了(iload_1 就是指讀取局部變量1 即 源碼裏的 i)it
條件判斷成立了那麼就執行For循環體了:
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 11: iload_1 12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
這三行結果就是執行了 System.out.println(i); 這句代碼
這裏的 #2 和 #3 表明的意思能夠在 常數池 裏找到了,因此在使用 javap命令的時候我用了 -v 參數來方便理解了
既然循環體執行完了,那麼接着就得更新循環變量了:
15: iinc 1, 1
即 ++i; 語句
最後就是跳到判斷語句的地方了:
18: goto 2
For循環的簡單分析就這樣了,有誤或不妥處歡迎指正