【java】foreach是如何實現的?
阿新 • • 發佈:2018-12-30
1.正文
因為想要了解編譯器是如何實現foreach功能的,就先寫一個foreach迴圈,看看位元組碼長啥樣。
public class ForEach {
List<String> list;
public void display1(){
for(String s : list){
System.out.println(s);
}
}
}
位元組碼就長下面這個樣子:
// Method descriptor #10 ()V /*V代表返回值是void*/ // Stack: 2, Locals: 3 /*運算元棧需要2個slot,區域性變量表需要3個slot*/ public void display1(); 0 aload_0 [this] /*將this指標推至棧頂*/ 1 getfield ambigous.ForEach.list : java.util.List [19] /*獲得域List物件,壓入棧頂*/ 4 invokeinterface java.util.List.iterator() : java.util.Iterator [21] [nargs: 1] /*呼叫interface的iterator方法獲得iterator物件*/ 9 astore_2 /*將其存到區域性變量表的第三個slot中(此時第一個是this,第二個空)*/ 10 goto 30 /*跳轉*/ 13 aload_2 /*將iterator物件推到棧頂*/ 14 invokeinterface java.util.Iterator.next() : java.lang.Object [27] [nargs: 1] /*呼叫iterator的next方法*/ 19 checkcast java.lang.String [33]/*checkcast型別安全檢查*/ 22 astore_1 [s] /*將s存到第二塊slot*/ 23 getstatic java.lang.System.out : java.io.PrintStream [35] /*獲取靜態System.out物件*/ 26 aload_1 [s] /*將s推到棧頂*/ 27 invokevirtual java.io.PrintStream.println(java.lang.String) : void [41] /*呼叫out.println方法*/ 30 aload_2 /*將iterator物件推到棧頂*/ 31 invokeinterface java.util.Iterator.hasNext() : boolean [47] [nargs: 1] /*呼叫iterator.hasNext方法*/ 36 ifne 13 /*如果結果非0,即true,跳轉*/ 39 return /*返回*/
可以看出對於foreach的執行最終轉換成了對iterator的呼叫。那麼我們再對比下顯示使用iterator程式碼的位元組碼:
位元組碼:public class ForEach { List<String> list; public void display1(){ for(String s : list){ System.out.println(s); } } public void display2(){ Iterator<String> it = list.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } }
// Method descriptor #10 ()V // Stack: 2, Locals: 2 public void display2(); 0 aload_0 [this] 1 getfield ambigous.ForEach.list : java.util.List [19] 4 invokeinterface java.util.List.iterator() : java.util.Iterator [21] [nargs: 1] 9 astore_1 [it] 10 goto 28 13 getstatic java.lang.System.out : java.io.PrintStream [35] 16 aload_1 [it] 17 invokeinterface java.util.Iterator.next() : java.lang.Object [27] [nargs: 1] 22 checkcast java.lang.String [33] 25 invokevirtual java.io.PrintStream.println(java.lang.String) : void [41] 28 aload_1 [it] 29 invokeinterface java.util.Iterator.hasNext() : boolean [47] [nargs: 1] 34 ifne 13 37 return
看~是不是驚人的相似!其實並不驚人,一切都在預料之中。哈哈。
那麼為什麼此時區域性變量表只需要2個slot就夠了呢?
因為第一段程式碼中slot先後存了this指標、list中的元素即區域性變數s、iterator物件;而第二段程式碼中沒有String的臨時變數,只有this指標和iterator物件it。
那麼兩段程式碼棧為什麼都用了兩個slot呢?
因為其實第一段程式碼在23-26的時候棧才存滿,棧底是out,棧頂是s。其他時候棧都未滿。第二段在13-16的時候棧滿,棧底依舊out,棧頂是iterator物件it。
2.References
java forEach實現原理
http://blog.csdn.net/a596620989/article/details/6930479