天天看點

JVM的class檔案結構詳解(三)

2.4 通路控制

在常量池結束之後是2位元組的通路控制

表示這個class檔案是類/接口、是否被public/abstract/final修飾等.

由于這些标志都由是/否表示,是以可以用0/1表示.

通路标志為2位元組,可以表示16位标志,但JVM目前隻定義了8種,未定義的直接寫0.

JVM的class檔案結構詳解(三)
JVM的class檔案結構詳解(三)

Demo1.txt中的構造方法

JVM的class檔案結構詳解(三)

Demo1這個示例中,我們并沒有寫構造函數。

由此可見,

沒有定義構造函數時,會有隐式的無參構造函數

2.5 類索引、父類索引、接口索引集合

表示目前class檔案所表示類的名字、父類名字、接口們的名字.

它們按照順序依次排列,類索引和父類索引各自使用一個u2類型的無符号常量,這個常量指向CONSTANT_Class_info類型的常量,該常量的bytes字段記錄了本類、父類的全限定名.

由于一個類的接口可能有好多個,是以需要用一個集合來表示接口索引,它在類索引和父類索引之後.這個集合頭兩個位元組表示接口索引集合的長度,接下來就是接口的名字索引.

2.6 字段表的集合

2.6.1 什麼是字段表集合?

用于存儲本類所涉及到的成員變量,包括執行個體變量和類變量,但不包括方法中的局部變量。

每一個字段表隻表示一個成員變量,本類中所有的成員變量構成了字段表集合。

2.6.2 字段表結構的定義

JVM的class檔案結構詳解(三)
  • access_flags

    字段的通路标志。在Java中,每個成員變量都有一系列的修飾符,和上述class檔案的通路标志的作用一樣,隻不過成員變量的通路标志與類的通路标志稍有差別。

  • name_index

    本字段名字的索引。指向一個CONSTANT_Class_info類型的常量,這裡面存儲了本字段的名字等資訊。

  • descriptor_index

    描述符。用于描述本字段在Java中的資料類型等資訊(下面詳細介紹)

  • attributes_count

    屬性表集合的長度。

  • attributes

    屬性表集合。到descriptor_index為止是字段表的固定資訊,光有上述資訊可能無法完整地描述一個字段,是以用屬性表集合來存放額外的資訊,比如一個字段的值。(下面會詳細介紹)

2.6.3 什麼是描述符?

成員變量(包括靜态成員變量和執行個體變量) 和 方法都有各自的描述符。

對于字段而言,描述符用于描述字段的資料類型;

對于方法而言,描述符用于描述字段的資料類型、參數清單、傳回值。

在描述符中,基本資料類型用大寫字母表示,對象類型用“L對象類型的全限定名”表示,數組用“[數組類型的全限定名”表示。

描述方法時,将參數根據上述規則放在()中,()右側按照上述方法放置傳回值。而且,參數之間無需任何符号。

2.6.4 字段表集合的注意點

一個class檔案的字段表集合中不能出現從父類/接口繼承而來字段;

一個class檔案的字段表集合中可能會出現程式猿沒有定義的字段

如編譯器會自動地在内部類的class檔案的字段表集合中添加外部類對象的成員變量,供内部類通路外部類。

Java中隻要兩個字段名字相同就無法通過編譯。但在JVM規範中,允許兩個字段的名字相同但描述符不同的情況,并且認為它們是兩個不同的字段。

Demo1.txt中的程式入口main方法

JVM的class檔案結構詳解(三)
JVM的class檔案結構詳解(三)

2.7 方法表的集合

在class檔案中,所有的方法以二維表的形式存儲,每張表來表示一個函數,一個類中的所有方法構成方法表的集合。

方法表的結構和字段表的結構一緻,隻不過通路标志和屬性表集合的可選項有所不同。

JVM的class檔案結構詳解(三)

方法表的屬性表集合中有一張Code屬性表,用于存儲目前方法經編譯器編譯過後的位元組碼指令。

方法表集合的注意點

如果本class沒有重寫父類的方法,那麼本class檔案的方法表集合中是不會出現父類/父接口的方法表;

本class的方法表集合可能出現程式猿沒有定義的方法

編譯器在編譯時會在class檔案的方法表集合中加入類構造器和執行個體構造器。

重載一個方法需要有相同的簡單名稱和不同的特征簽名。JVM的特征簽名和Java的特征簽名有所不同:

Java特征簽名:方法參數在常量池中的字段符号引用的集合

JVM特征簽名:方法參數+傳回值