foreach循環也叫增強型的for循環,他是JDK 5.0的新特性(其他特性例如泛型等)
使用方法如下:
for(type element:array){....//coding here }
?
lambda java,其中關于foreach的優勢與局限性在迭代(二)文章中都有指出,并且在上一篇文章提出了關于foreach如何具體實現的問題。
我們通過反編譯.class文件(語法為:javap -verbose xxxx.class),得到了如下內容:
java final。其實反編譯后的信息很多,但是我只截取了最重要的兩部分。至于這兩部分分別代表什么,我們先來了解java的字節碼怎么讀取。當我講述完成的時候,相信也是能夠讀懂上面信息的時候。
?
首先我們打開.class文件:顯示如下:
Java foreach??
很清晰的看到是一連串的十六進制組成,這就是匯編形成的字節碼,接下來我們對如何解讀字節碼進行進一步的分析:
?
首先,我們來看一副圖:
必須聲明元素類型foreach、
這幅圖就是字節碼的結構圖,組成部分就分別是這么幾個,我將分別進行闡述;
?
1)魔數(Magic Number)
四個字節的魔數,從我給出的.class文件看出,開頭的四個字節是cafebabe,當然這是十六進制的數,但是為什么是cafebabe。看看java的圖標吧:
list.foreach??
?
2)版本號:
版本號四個字節,前四個為次版本號,后四個為主版本號,在此,值為0x0000 0034,解析出來就是次版本號為0,主版本號為52;那么,從反編譯出來的第一幅圖可以看到:
java arraylist,
這就是反編譯出來的版本號,與我們分析的一致;
至此,前八個字節很簡單就被我們分析出來了。
?
3)常量池
java中foreach循環用法?接著就是常量池入口。
常量池是class文件中的資源倉庫,主要包括兩大類:字面量和符號引用。字面量如文本字符串,java申明中為final的值,而符號引用入類和接口的全局限定名,字段的名稱和描述符,方法的名稱和描述符。 具體怎么實現在內存內存中,則是虛擬機的工作,我們這里還是不要深入比較好。
在進行常量池分析的時候,我們先了解常量池類型表:
?
?
上面描述了11中數據類型的結構,但是jdk1.7后又增加了三種,分別是(CONSTANT_MethodHandle_info,CONSTANT_MethodType_info以及CONSTANT_InvokeDynamic_info)算起來一共是14中,接下來按照demo碼對他們進行解答:
0x0048:這是緊接著版本號的,因為常量池的數量不一定,所以我們在入口的時候需要定義一個u2類型的數據來記錄到底有多少個常量池,該十六進制表示有71個常量池,這里要注意:該十六進制轉換數值為72,但是實際只有71個常量池!!?縮影范圍為1-71,第0項被設計者規定空留出來了,這是.class文件格式所規定的。
所以我們接下來要翻譯71個常量池。(不可能的,我舉例子出來能夠引用就可以了):
?
#1: 0x07:tag值為7:class-info,一個U2類型縮影為:0x0002,即#2;
#2:0x01:tag值為1:utf-8info,長度:0x0019:byte長度其實就是這個描述的具體內容,是從一個字節大小擴展出去的。應該是25個字節(0x0019)。還記得我們使用16進制打開的.class文件么?旁邊有一串字符,其中包含亂碼,中間的某些字符串和16進制的值時一一對應的,采用的asc碼。所以,這一段字符的值和16進制對應關系如截圖所示:
當然長度只有25字節,所以在25字節過后,是下一個常量池信息了!也就是在07及其以后的數值已經是下一個常量池了。
?
上面兩個例子其實就可以很好的解釋了,我這個例子的常量池有點長,我這里給出另外一位博主的網站地址,他所舉出的例子是很詳細的。http://www.importnew.com/24088.html。
我們可以看到,我們自己分析的結果其實就是反編譯出來的結果的第一部分。
4)Access_Flag訪問標志:
訪問標志信息包括這個.class文件是類還是接口,是不是public,是不是abstract,如果是類是否被聲明成final:
下面給出這個標志表格:
而我們在給出的.class文件中會發現,此處的標志信息為0x0021。這其實是很簡單,0x0020與0x0001的并集。即包含了兩個標志信息,這里匯編器自動將這個類歸類為超類。
?
5)類索引
類索引引用與確定類的全限定名
0x0001表示引用第一個索引,就是:#1.#2.iteretorTest/TestIterator.
6)超類索引
與類索引一致,確定超類的全限定名
0x0003表示引用第三個索引,就是:#3.#4. java/lang/Object;
7)接口索引
可以看到接口索引為2+n個字節,而我們的測試程序沒有應用接口,所以我們的前兩個字節是0x0000。那么,也不存在n的情況。但是如果有接口,這個時候后面直接跟著接口的索引。
8)字段表集合
字段表用于描述類和接口中聲明的變量。這里的字段包含了類級別變量以及實例變量,但是不包括方法內部聲明的局部變量。
而且,字段表也是2+n個字節,在本文的例子中,我們沒有變量,所以在.class文件中,這里為0x0000;
但是,實際上,很多情況下都會涉及到包含變量。
這個時候,我們給出字段表集合,來對這段字段進行分析;
同樣,用上面給出博主的文章中的例子可以在此分析一下。
?
下面就是方法,我們將在下一篇文章中寫出,方法的解析就會相交前面的復雜很多,其中某些字符的含義需要單獨解釋,例如<init>,()V,我將會用一個單獨的篇章進行方法的字節碼解析。
?