摘要:對象創建與訪問指令雖然類實例和數組都是對象,但虛擬機對類實例和數組的創建和操作使用了不同的字節碼指令。異常處理指令在虛擬機中,處理異常語句不是由字節碼指令來實現的,而是采用異常表的方式。
《深入理解Java虛擬機:JVM高級特性與最佳實踐(第二版》讀書筆記與常見面試題總結
本節常見面試題(推薦帶著問題閱讀,問題答案在文中都有提到):
簡單介紹一下Class類文件結構(常量池主要存放的是那兩大常量?Class文件的繼承關系是如何確定的?字段表、方法表、屬性表主要包含那些信息?)
1 概述 計算機雖然只能識別0和1,但是越來越多的程序語言選擇了與操作系統和機器指令集無關無關的、平臺中立的格式作為程序編譯后的存儲格式。Java虛擬機不和包括Java在內的任何語言綁定,只與 "Class文件" 這種特定的二進制文件所關聯,Class文件中包含了Java虛擬機指令集合符號表以及若干其它輔助信息。Java虛擬機作為一個通用的、機器無關的執行平臺,任何其他語言都可以將其作為語言的產品交付媒介。
Class文件是一組以8位字節為基礎的二進制流,各個數據項目嚴格按照順序緊湊地排列在Class文件之中,中間沒有添加任何分隔符,這使得整個Class文件中存儲的內容幾乎全部是程序運行的必要數據,沒有空隙存在。當遇到需要占用8位字節以上空間的數據項時,則會按照高位在前的方式分割成若干個8位字節進行存儲。
Class文件格式采用一種類似于C語言結構體的偽結構來存儲數,這種偽結構有兩種數據類型:無符號數和表。
這里需要重復提一下,Class文件結構不像XML等描述語言,由于它沒有任何分割符號,所以無論是數量甚至于數據存儲的字節序這樣的細節都被嚴格限定,哪個字節代表什么含義,長度是多少,先后順序如何,都不允許改變。
2.1 魔數與Class文件版本每個Class文件的頭四個字節稱為魔數(Magic Number),它的唯一作用是確定這個文件是否為一個能被虛擬機接收的Class文件。緊接著魔數的四個字節存儲的是Class文件的版本號:第五和第六是次版本號,第七和第八是主版本號。
2.2 常量池緊接著主次版本號之后的是常量池入口,常量池可以理解為Class文件之中的資源倉庫,它是Class文件結構中與其他項目關聯最多的數據類型,也是占用Class文件空間最大的數據項目之一,同時它還是在Class文件中第一個出現的表類型數據項目。
常量池主要存放兩大常量:字面量和符號引用。字面量比較接近于java語言層面的的常量概念,如文本字符串、聲明為final的常量值等。而符號引用則屬于編譯原理方面的概念。包括下面三類常量:
類和接口的全限定名
字段的名稱和描述符
方法的名稱和描述符
2.3訪問標志在常量池結束之后,緊接著的兩個字節代表訪問標志,這個標志用于識別一些類或者接口層次的訪問信息,包括:這個Class是類還是接口,是否為public或者abstract類型,如果是類的話是否聲明為final等等。具體標志位及標志的含義如下圖所示:
2.4 類索引、父類索引與接口索引集合類索引、父類索引與接口索引集合都按順序排列在訪問標志之后,Class文件由這三項數據來確定這個類的繼承關系。類索引用于確定這個類的全限定名,父類索引用于確定這個類的父類的全限定名,由于java語言的單繼承,所以父類索引只有一個,除了java.lang.Object之外,所有的java類都有父類,因此除了java.lang.Object外,所有java類的父類索引都不為0。接口索引集合用來描述這個類實現了那些接口,這些被實現的接口將按implents(如果這個類本身是接口的話則是extends)后的接口順序從左到右排列在接口索引集合中。
2.5 字段表集合字段表(field info)用于描述接口或類中聲明的變量。字段包括類級變量以及實例變量,但不包括在方法內部聲明的局部變量。
我們可以想一想在java中描述一個字段可以包含什么信息呢?
字段的作用域(public ,private,protected修飾符),是實例變量還是類變量(static修飾符)、可變性(final)、并發可見性(volatile修飾符,是否強制從主內存讀寫)、可否被序列化(transient修飾符)、字段數據類型、字段名稱。上述這些信息中,各個修飾符都是布爾值,要么有某個修飾符,要么沒有,很適合使用標志位來表示。而字段叫什么名字、字段被定義為什么數據類型這些都是無法固定的,只能引用常量池中常量來描述。
2.6方法表集合Class文件存儲格式中對方法的描述與對字段的描述幾乎采用了完全一致的方式。方法標的結構如同字段表一樣,依次包括了訪問標志、名稱索引、描述符索引、屬性表集合幾項。
在這里稍微提一下,因為volatile修飾符和transient修飾符不可以修飾方法,所以方法表的訪問標志中沒有這兩個對應的標志,但是增加了synchronized、native、abstract等關鍵字修飾方法,所以也就多了這些關鍵字對應的標志。
在Class文件,字段表,方法表中都可以攜帶自己的屬性表集合,以用于描述某些場景專有的信息。與Class文件中其它的數據項目要求的順序、長 度和內容不同,屬性表集合的限制稍微寬松一些,不再要求各個屬性表具有嚴格的順序,并且只要不與已有的屬性名重復,任何人實現的編譯器都可以向屬性表中寫 入自己定義的屬性信息,Java虛擬機運行時會忽略掉它不認識的屬性。
3 字節碼指令簡介 3.1字節碼與數據類型在java虛擬機的指令集中,大多數的指令都包含了其操作所對應的數據類型信息,例如iload指令用于從局部變量表中加載int類型的數據到操作數棧中,而fload指令加載的則是float類型的數據。這兩條指令的操作在虛擬機內部可能是同一段代碼實現的,但在Class文件中它們必須擁有各自獨立的操作碼。
大部分的指令都沒有支持整數類型byte、char、short甚至沒有任何指令支持boolean類型。大多數對于byte、char、short、boolean類型的操作,實際上都是使用相應的int類型作為運算符類型。
3.2 加載和存儲指令加載和存儲指令用于將數據在棧幀中的局部變量表和操作數棧之間來回傳輸。
3.3 運算指令運算或算術指令用于對操作數棧上的值進行某種特定運算,并把結果重新存入操作棧頂。
大體上算術指令可以分為兩種:對整型數據和對浮點數據進行運算指令。(由于沒有byte、char、short、boolean類型,所以對這類數據的運算應使用int類型指令代替)
類型轉換指令可以將兩種不同的數值類型進行相互轉換。(比如int類型轉換為float類型)
小范圍到大范圍類型安全轉換,無需顯式的轉換指令,否則必須顯式的使用轉換指令來完成。
雖然類實例和數組都是對象,但java虛擬機對類實例和數組的創建和操作使用了不同的字節碼指令。
如同操作數據結構中的棧一樣,java虛擬機也提供了一些用于直接操作操作數棧的指令,如:
3.7 控制轉移指令可以認為控制轉移指令就是在有條件或無條件地修改PC寄存器的值。
3.8 方法調用和返回指令invokevirtual 指令用于調用對象的實例方法
invokeinterface指令用于調用接口方法
invokespecial指令用于調用一些需要特殊處理的實例方法
invokestatic指令用于調用類方法(static方法)
invokedynamic指令用于在運行時動態解析出調用點限定符所使用的方法。
方法調用指令與數據類型無關,而方法返回指令是根據返回值的類型區分的。
3.9 異常處理指令在java虛擬機中,處理異常(catch語句)不是由字節碼指令來實現的,而是采用異常表的方式。
3.10 同步指令java虛擬機可以支持方法級的同步和方法內部一段指令序列的同步,這兩種同步結構使用管程(Monitor)來支持的。
4 虛擬機實現的兩種方式將輸入的java虛擬機代碼在加載或執行時翻譯成另外一種虛擬機的指令集
將輸入的java虛擬機代碼在加載或執行時翻譯成宿主主機CPU的本地指令集(即JIT代碼生成技術)
5 class文件結構的發展Class文件結構已經有十多年歷史了,這10多年間,java技術體系有了翻天覆地的變化,但是Class文件結構一直處于比較穩定的狀態,Class文件的主體結構、字節碼指令的語義和數量幾乎沒有出現過變動,所有Class文件格式的改進,都集中在向訪問標志、屬性表這些在設計上就可擴展的數據結構中添加內容。
總結:Class文件是java虛擬機執行引擎的數據入口,也是java技術體系的基礎構成之一。本節主要介紹了Class文件結構中的各個部分,以及每個部分的定義、數據結構和使用方法。
歡迎關注我的微信公眾號:"Java面試通關手冊"(一個有溫度的微信公眾號,期待與你共同進步~~~堅持原創,分享美文,分享各種Java學習資源):
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69343.html
摘要:二驗證驗證主要是為了確保文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機的自身安全。五初始化類的初始化階段是類加載過程的最后一步,該階段才真正開始執行類中定義的程序代碼或者說是字節碼。 關注我,每天三分鐘,帶你輕松掌握一個Java相關知識點。 虛擬機(JVM)經常出現在我們面試中,但是工作中卻很少遇到,導致很多同學沒有去了解過。其實除了應付面試,作為java程序員,了解...
摘要:虛擬機運行時數據區分為以下幾個部分。程序計數器也是在虛擬機規范中唯一沒有規定任何異常情況的區域。在方法運行期間不會改變局部變量表的大小。長度在位和位的虛擬機中,分別為官方稱它為。 Java虛擬機運行時數據區 詳解 2.1 概述 本文參考的是周志明的 《深入理解Java虛擬機》第二章 ,為了整理思路,簡單記錄一下,方便后期查閱。 2.2 運行時數據區域 Java虛擬機在Java程序運行時...
摘要:由虛擬機加載的類,被加載到虛擬機內存中之后,虛擬機會讀取并執行它里面存在的字節碼指令。虛擬機中執行字節碼指令的部分叫做執行引擎。 什么是Java虛擬機? 作為一個Java程序員,我們每天都在寫Java代碼,我們寫的代碼都是在一個叫做Java虛擬機的東西上執行的。但是如果要問什么是虛擬機,恐怕很多人就會模棱兩可了。在本文中,我會寫下我對虛擬機的理解。因為能力所限,可能有些地方描述的不夠欠...
閱讀 1478·2021-10-14 09:43
閱讀 1442·2021-10-09 09:58
閱讀 1937·2021-09-28 09:42
閱讀 3727·2021-09-26 09:55
閱讀 1752·2021-08-27 16:23
閱讀 2755·2021-08-23 09:46
閱讀 906·2019-08-30 15:55
閱讀 1405·2019-08-30 15:54