《Java虛擬機原理圖解》 1.一、class文件基本組織結構

[last updated: 2014/11/19 09:06]         
java

      做爲Java程序員。咱們知道。咱們寫好的.java 源碼,最後會被Java編譯器編譯成後綴爲.class的文件,該類型的文件是由字節組成的文件。又叫字節碼文件。那麼。class字節碼文件中面到底是有什麼呢?它又是如何組織的呢?讓咱們先來大概瞭解一下他的組成結構吧。程序員



NO1. 魔數(magic)

      所有的由Java編譯器編譯而成的class文件的前4個字節都是「0xCAFEBABE」  
      它的做用在於:當JVM在嘗試載入某個文件到內存中來的時候,會首先推斷此class文件有沒有JVM以爲可以接受的「簽名」,即JVM會首先讀取文件的前4個字節,推斷該4個字節是不是「0xCAFEBABE」,假設是,則JVM會以爲可以將此文件看成class文件來載入並使用。

數組


NO2.版本(minor_version,major_version)

      隨着Java自己的發展,Java語言特性和JVM虛擬機也會有對應的更新和加強。眼下咱們能夠用到的JDK版本號如:1.5,1.6,1.7,還有現如今最新的1.8。公佈新版本號的目的在於:在原有的版本號上添加新特性和對應的JVM虛擬機的優化。而隨着主版本號公佈的次版本號,則是改動對應主版本號上出現的bug。咱們平時僅僅需要關注主版本號就好了。jvm

主版本號號和次版本號號在class文件裏各佔兩個字節,副版本號號佔用第五、6兩個字節,而主版本號號則佔用第7,8兩個字節。JDK1.0的主版本號號爲45,之後的每個新主版本號都會在原先版本號的基礎上加1。若現在使用的是JDK1.7編譯出來的class文件,則相應的主版本號號應該是51,相應的7,8個字節的十六進制的值應該是 0x33。工具

      一個 JVM實例僅僅能支持特定範圍內的主版本 (MiMj) 和 0 至特定範圍內 (0 至 m) 的副版本。若是一個 Class 文件的格式版本爲 V。 僅當Mi.0 ≤ v ≤ Mj.m成立時,這個 Class 文件才幹夠被此 Java 虛擬機支持。不一樣版本號的 Java 虛擬機實現支持的版本號號也不一樣,高版本號號的 Java 虛擬機實現可以支持低版本號號的 Class 文件,反之則不成立。優化

     JVM在載入class文件的時候。會讀取出主版本。而後比較這個class文件的主版本和JVM自己的版本。假設JVM自己的版本 < class文件的版本。JVM會以爲載入不了這個class文件,會拋出咱們經常見到的"java.lang.UnsupportedClassVersionError: Bad version number in .class file " Error 錯誤。反之。JVM會以爲可以載入此class文件。繼續載入此class文件。
ui

     

    小貼士:this

1. 有時候咱們在執行程序時會拋出這個Error 錯誤:"java.lang.UnsupportedClassVersionError: Bad version number in .class file"。lua

上面已經揭示了出現這個問題的解決辦法,就是在於當前嘗試載入class文件的JVM虛擬機的版本號 低於class文件的版本號。解決方法:1.又一次使用當前jvm編譯源碼,而後再執行代碼。2.將當前JVM虛擬機更新到class文件的版本號。spa

2. 如何查看class文件的版本?

 可以藉助於文本編輯工具。直接查看該文件的7,8個字節的值。肯定class文件是什麼版本號的。


固然快捷的方式使用JDK自帶的javap工具,如當前有Programmer.class 文件,進入此文件所在的文件夾,而後運行 」javap -v Programmer「,結果會相似例如如下所看到的:

    



NO3.常量池計數器(constant_pool_count)

 常量池是class文件裏很重要的結構,它描寫敘述着整個class文件的字面量信息。 常量池是由一組constant_pool結構體數組組成的,而數組的大小則由常量池計數器指定。常量池計數器constant_pool_count 的值 =constant_pool表中的成員數+ 1。constant_pool表的索引值僅僅有在大於 0 且小於constant_pool_count時纔會被以爲是有效的。


NO4.常量池數據區(constant_pool[contstant_pool_count-1])

常量池,constant_pool是一種表結構,它包括 Class 文件結構及其子結構中引用的所有字符串常量、 類或接口名、字段名和其餘常量。 常量池中的每一項都具有一樣的格式特徵——第一個字節做爲類型標記用於識別該項是哪一種類型的常量。稱爲 「tag byte」 。常量池的索引範圍是 1 至constant_pool_count−1。常量池的詳細細節咱們會稍後討論。


NO6.訪問標誌(access_flags)

       訪問標誌。access_flags 是一種掩碼標誌,用於表示某個類或者接口的訪問權限及基礎屬性。

      




NO7.類索引(this_class)

       類索引。this_class的值必須是對constant_pool表中項目的一個有效索引值。constant_pool表在這個索引處的項必須爲CONSTANT_Class_info 類型常量,表示這個 Class 文件所定義的類或接口。




NO8.父類索引(super_class)

     父類索引,對於類來講,super_class 的值必須爲 0 或者是對constant_pool 表中項目的一個有效索引值。

假設它的值不爲 0。那 constant_pool 表在這個索引處的項必須爲CONSTANT_Class_info 類型常量,表示這個 Class 文件所定義的類的直接父類。當前類的直接父類,以及它所有間接父類的access_flag 中都不能帶有ACC_FINAL 標記。對於接口來講,它的Class文件的super_class項的值必須是對constant_pool表中項目的一個有效索引值。constant_pool表在這個索引處的項必須爲表明 java.lang.Object CONSTANT_Class_info 類型常量 。假設 Class 文件的 super_class的值爲 0,那這個Class文件僅僅多是定義的是java.lang.Object類,僅僅有它是惟一沒有父類的類。



NO9.接口計數器(interfaces_count)

      接口計數器,interfaces_count的值表示當前類或接口的直接父接口數量。




NO10.接口信息數據區(interfaces[interfaces_count])

      接口表。interfaces[]數組中的每個成員的值必須是一個對constant_pool表中項目的一個有效索引值。 它的長度爲 interfaces_count。每個成員 interfaces[i]  必須爲 CONSTANT_Class_info類型常量。當中 0 ≤ i <interfaces_count。在interfaces[]數組中,成員所表示的接口順序和相應的源碼中給定的接口順序(從左至右)同樣。即interfaces[0]相應的是源碼中最左邊的接口。



NO11.字段計數器(fields_count)

      字段計數器。fields_count的值表示當前 Class 文件 fields[]數組的成員個數。

fields[]數組中每一項都是一個field_info結構的數據項,它用於表示該類或接口聲明的類字段或者實例字段。


NO12.字段信息數據區(fields[fields_count])

      字段表,fields[]數組中的每個成員都必須是一個fields_info結構的數據項,用於表示當前類或接口中某個字段的完整描寫敘述。

fields[]數組描寫敘述當前類或接口聲明的所有字段,但不包含從父類或父接口繼承的部分。



NO13.方法計數器(methods_count)

     方法計數器。 methods_count的值表示當前Class 文件 methods[]數組的成員個數。Methods[]數組中每一項都是一個 method_info 結構的數據項。



NO14.方法信息數據區(methods[methods_count])

      方法表,methods[] 數組中的每個成員都必須是一個 method_info 結構的數據項。用於表示當前類或接口中某個方法的完整描寫敘述。假設某個method_info 結構的access_flags 項既沒有設置 ACC_NATIVE 標誌也沒有設置ACC_ABSTRACT 標誌。那麼它所相應的方法體就應當可以被 Java 虛擬機直接從當前類載入,而不需要引用其餘類。 method_info結構可以表示類和接口中定義的所有方法,包含實例方法、類方法、實例初始化方法方法和類或接口初始化方法方法 。

methods[]數組僅僅描寫敘述當前類或接口中聲明的方法,不包含從父類或父接口繼承的方法。




NO15.屬性計數器(attributes_count)

     屬性計數器,attributes_count的值表示當前 Class 文件attributes表的成員個數。

attributes表中每一項都是一個attribute_info 結構的數據項。


NO16.屬性信息數據區(attributes[attributes_count])

     屬性表。attributes 表的每個項的值必須是attribute_info結構。

    在Java 7 規範裏。Class文件結構中的attributes表的項包含下列定義的屬性: InnerClasses  、 EnclosingMethod 、 Synthetic  、Signature、SourceFile,SourceDebugExtension 、Deprecated、RuntimeVisibleAnnotations 、RuntimeInvisibleAnnotations以及BootstrapMethods屬性。

      對於支持 Class 文件格式版本爲 49.0 或更高的 Java 虛擬機實現,必須正確識別並讀取attributes表中的SignatureRuntimeVisibleAnnotationsRuntimeInvisibleAnnotations屬性。對於支持Class文件格式版本爲 51.0 或更高的 Java 虛擬機實現,必須正確識別並讀取 attributes表中的BootstrapMethods屬性。

Java 7 規範 要求任一 Java 虛擬機實現可以本身主動忽略 Class 文件的 attributes表中的若干 (甚至全部) 它不可識別的屬性項。

不論什麼本規範沒有定義的屬性不能影響Class文件的語義,僅僅能提供附加的描寫敘述信息 。


依據上述的敘述,咱們可以將class的文件組織結構歸納成以如下這個結構體:






參考書目:

Java虛擬機規範(Java SE 7)中文版(Java_Virtual_Machine_Specification_Java_SE_7)

[深刻理解Java虛擬機:JVM高級特性與最佳實踐].周志明



做者的話

    本文是《Java虛擬機原理圖解》的第一篇。假設您有興趣,請關注該系列的其它文章~

   認爲本文不錯,順手點個贊哦~~您的鼓舞,是我繼續分享知識的強大動力。




-----------------------------------------------------------------------------------------------------------------------------------------

                                                                                本文源自  http://blog.csdn.net/luanlouis/,如需轉載,請註明出處,謝謝!
相關文章
相關標籤/搜索