而這每一種類型都有自己的結構,具體如下:
4.訪問標志(access_flags):常量池之后,緊接著的兩個字節代表訪問標志,這個標志用于識別一些類或者接口層次的訪問信息(比如這個class是否是public是否是final等等),具體如下:
5.類索引,父類索引,接口索引:類索引和父類索引都是一個u2類型的數據,而接口索引集合時一組u2類型的數據的集合,class文件中由這三項數據來確定這個類的繼承關系。類索引用于確定這個類的全限定名,父類索引用于確定這個類的父類的全限定名(除了kava.lang.Object以外所有類的父類索引均不為0)。接口索引集合用來描述這個類實現了哪些接口。 類索引和父類索引用兩個u2類型的索引值表示,它們各自指向一個類型為CONSTANT_Class_info的類描述符常量,通過CONSTANT_Class_info類型的常量中的索引值可以找到定義在CONSTANT_Utf8_info類型的常量中的全限定名字符串。6.字段表集合:字段表集合用于描述接口或者類中聲明的變量。字段包括了類級變量或者實例級變量,但是不包括方法內部聲明的變量。其結構如下:
首先兩個字節是訪問符,這跟類中的access_flags非常類似,都是u2數據類型,其中可以設置的標志位的含義如下:
其次是name_index,這是一個指向常量池的引用,代表字段的簡單名稱(指沒有類型和參數修飾的方法或者字段名稱);緊接著兩個字節是descriptor_index,字段方法描述符。描述符的作用是用來描述字段的數據類型、方法的參數列表(包括數量,類型以及順序)和返回值。根據規則,基本數據類型及代表無返回值的void類型都用一個大寫字符來表示,而對象類型則用字符L加對象的全限定名來表示。
對于數組類型,每一維度會使用‘[’字符來表示,比如定義java.lang.String[][]類型的二維數組,將被記錄為[[Ljava/lang/String,而整型數組則標記為[I。用描述符來描述方法時,按照縣參數列表,后返回值的順序,參數列表按照參數的嚴格順序放在一組小括號”()“之內。比如void func(),描述符為()V,void foo(int[] a,cha b),描述為([IC)V.描述符之后是屬性表集合(attributes,當然之前是屬性表計數器),它用于存儲一些額外的信息。7.方法表集合:內容跟屬性表集合基本一致,下面是其結構:
但是access_flags訪問標志與字段表是有區別的:
另外,方法里的java代碼,經過javac編譯器編譯成字節碼指令后,將存放在方法的屬性表集合(attributes)中的一個名為code的屬性里面.8.屬性表集合:在class文件、字段表、方法表中都可以攜帶字節的屬性表集合,用于描述某些場景專有的信息。屬性表中的數據項目不需要有嚴格的順序,java虛擬機在運行時會自動的忽略掉不認識的屬性,其中系統預定義了9種虛擬機應該識別的屬性,如下:
每一種屬性的名稱都是引用的常量池中的常量,屬性值的結構可以自定義,但是需要符合下面的結構:
重點介紹下Code屬性。Code屬性:java程序方法體里面的代碼經過javac編譯器處理后,最終變為字節碼指令存儲在code屬性中,code屬性出現在方法表的屬性集合中,并非所有方法表都必須有code屬性,比如抽象方法,code屬性結構如下:
首先attribute_name_index是一項指向常量池的引用(CONSTANT_Utf8_info),值為Code,它代表屬性名稱;attribute_length代表屬性值的長度;max_stack代表操作數棧的最大深度,在方法執行的任意時刻,操作數棧都不會超過這個深度,虛擬機運行的時候將根據這個值來分配棧幀中的操作數棧深度。緊接著max_locals代表局部變量表所需的存儲空間。這里需要注意的是,max_locals的單位是slot,slot即槽,是虛擬機為局部變量分配內存所使用的最小單位。基本數據類型除了double和long都占用1slot,double和long占用2slot,另外reference和returnAddress占1slot;code_length和code用來存儲java源程序編譯后生成的字節碼指令。新聞熱點
疑難解答