java虛擬機規範中的java虛擬機的跨語言性及跨平臺性,多半歸功於定義中的Class文件,Class文件解耦了虛擬機平臺的具體實現與具體的編程語言,也業務開發角度理解,能夠將它抽象成接口對接文檔(固然只是爲了方便理解),既然是已經擬定的文檔,那麼必然存在必定的規則,在瞭解具體Class文件規範以前須要對Class文件有一個總體的認識。java
首先Class文件是一組以8位字節爲基礎單位的二進制流,各個數據項目嚴格按照順序緊湊地排列在Class文件之中,中間沒有任何分隔符,這使得整個Class文件中存儲的內容幾乎所有是程序運行的必要數據,沒有空隙存在。當須要須要佔用8位字節以上空間的數據項時,則會按照高位在前的方式分割成若干個8位字節進行存儲。編程
根據java虛擬機規範的規定,Class文件格式採用相似於c語言中結構體的僞結構(僅僅是數據組合的一種既定方式)來存儲數據,在該僞結構中只有兩種數據類型:無符號數和表。安全
無符號數屬於基本的數據類型,以u一、u二、u四、u8來分別表明1個字節、2個字節、4個字節、和8個字節的無符號數,經常使用於表述數字(好比常量池的count、方法表count、屬性表count等)、索引引用、數值量或按照UTF-8編碼構成的字符串值。編程語言
表在結構上是由無符號數和其餘表構成的用語表述具備層次關係的複合結構,整個class文件也能夠當作是一張特殊的表。性能
在介紹具體的Class文件結構以前,須要提醒的是class文件中對於字節碼的順序、長度都有嚴格的定義,具體的虛擬機實現必須遵循這樣的規範(否則一次編譯處處運行只能是夢想),固然Class文件規範中也容許虛擬機實如今遵循java標準虛擬機規範的前提下自由定義其餘屬性以提升虛擬機在某方面的性能。編碼
Class文件結構:spa
不管是無符號數仍是表,當須要描述同一類型但數量不定的多個數據時,常常會使用一個前置的容量計數器加若干個連續的數據項的形式(這應該比較好理解,不少協議中都用了相似的思想,在數據報文頭中先告訴接受端報文內容的總體信息,根據這些信息去解析報文數據,如netty中的編碼器和解碼器、http協議等),這時稱這一系列連續的某一類型的數據爲某一類型的集合。.net
詳解Class文件結構:netty
爲方便進一步理解,將使用下面的例子進行講解:code
package org.lucas.clazz; /** * Created by BG260733 on 2017-04-09. */ public class TestClass { private int n; private static final int m = 5; public int inc() { return m + n; } }
說明:如下class文件均由winHex十六進制打開。
magic:
每一個class文件的頭4個字節稱爲魔數(Magic Number),它的惟一做用時肯定這個文件是否爲一個能被虛擬機接受的class文件(不表明能成功解析)。不少文件存儲標準中都是在文件內容中嵌入魔術來進行身份識別,之因此不使用文件名(包括後綴)來做爲文件的識別方式,主要是出於安全方面的考慮,文件名可能會被外部頻繁改動。Class文件的魔術值爲:OxCAFEBABY,是否是自帶浪漫氣息。
minor_version
僅接着魔數後面的第5個和第6個兩個字節,表示可以解析執行該class文件的虛擬機次版本號。
major_version
第7個和第8個兩個字節,表示可以解析執行該class文件的虛擬機主版本號。
下表列出了從JDK1.1到JDK1.7,主流JDK版本編譯器輸出的默認和可支持的Class文件版本號。
-target標誌表示容許編譯器生成特定版本的Java類文件格式。
-source標誌表示容許編譯器將新的語言構造(如Lambda表達式、try-with-resources以及switch中使用字符串等等)看作錯誤。一些新語言特性(好比Lambda表達式)須要使用特定的字節碼功能(好比invokedynamic),所以,-source指定的版本比-target指定的版本還新每每是不可能的。
博主本打算將Class文件全部內容由一篇文章講述清楚、但實際編寫過程當中發現待表述的信息量仍是太大,爲了方便讀者閱讀,特將此篇分爲五到六篇文章,未完待續~