講完了class文件中的常量池,咱們就至關於克服了class文件中最麻煩的模塊了。如今,咱們來看一下class文件中緊接着常量池後面的幾個東西:訪問標誌、類索引、父類索引、接口索引集合。html
好,讓咱們來一一擊破它們,看看它們究竟是什麼東西。java
訪問標誌(access_flags)緊接着常量池後,佔有兩個字節,總共16位,以下圖所示:jvm
當JVM在編譯某個類或者接口的源代碼時,JVM會解析出這個類或者接口的訪問標誌信息,而後,將這些標誌設置到訪問標誌(access_flags)這16個位上。JVM會考慮以下設置以下訪問表示信息:ide
a. 咱們知道,每一個定義的類或者接口都會生成class文件(這裏也包括內部類,在某個類中定義的靜態內部類也會單獨生成一個class文件)。ui
對於定義的類,JVM在將其編譯成class文件時,會將class文件的訪問標誌的第11位設置爲1 。第11位叫作ACC_SUPER標誌位;this
對於定義的接口,JVM在將其編譯成class文件時,會將class文件的訪問標誌的第8位 設置爲 1 。第8位叫作ACC_INTERFACE標誌位;
luab. class文件表示的類或者接口的訪問權限有public類型的和包package類型的。spa
若是類或者接口被聲明爲public類型的,那麼,JVM將其編譯成class文件時,會將class文件的訪問標誌的第16位設置爲1 。第16位叫作ACC_PUBLIC標誌符;
.netc. 類是否爲抽象類型的,即咱們定義的類有沒有被abstract關鍵字修飾,即咱們定義的類是否爲抽象類。3d
若是咱們形如:
public abstract class MyClass{......}
定義某個類時,JVM將它編譯成class文件的時候,會將class文件的訪問標誌的第7位設置爲1 。第7位叫作ACC_ABSTRACT標誌位。 另外值得注意的是,對於定義的接口,JVM在編譯接口的時候也會對class文件的訪問標誌上的ACC_ABSTRACT標誌位設置爲 1;d. 該類是否被聲明瞭final類型,即表示該類不能被繼承。
此時JVM會在編譯class文件的過程當中,會將class文件的訪問標誌的第12位設置爲 1 。第12位叫作ACC_FINAL標誌位;
e.若是咱們這個class文件不是JVM經過java源代碼文件編譯而成的,而是用戶本身經過class文件的組織規則生成的,那麼,通常會對class文件的訪問標誌第4位設置爲 1 。經過JVM編譯源代碼產生的class文件此標誌位爲 0,第4位叫作ACC_SYNTHETIC標誌位;
f. 枚舉類,對於定義的枚舉類如:public enum EnumTest{....},JVM也會對此枚舉類編譯成class文件,這時,對於這樣的class文件,JVM會對訪問標誌第2位設置爲 1 ,以表示它是枚舉類。第2位叫作ACC_ENUM標誌位;
g. 註解類,對於定義的註解類如:public @interface{.....},JVM會對此註解類編譯成class文件,對於這樣的class文件,JVM會將訪問標誌第3位設置爲1,以表示這是個註解類,第3位叫作ACC_ANNOTATION標誌位。
當JVM肯定了上述標誌位的值後,就能夠肯定訪問標誌(access_flags)的值了。實際上JVM上述標誌會根據上述肯定的標誌位的值,對這些標誌位的值取或,便獲得了訪問標誌(access_flags)。以下圖所示:
舉例:定義一個最簡單的類Simple.java,使用編譯器編譯成class文件,而後觀察class文件中的訪問標誌的值,以及使用javap -v Simple 查看訪問標誌。
使用UltraEdit查看編譯成的class文件,以下圖所示:
package com.louis.jvm; public class Simple { }
上述的圖中黃色部分表示的是常量池部分,具體爲何是常量池部分不是本文的重點,有興趣的讀者能夠參考個人《Java虛擬機原理圖解》系列關於常量池的博客,你就能夠很輕鬆地識別常量它們了。
常量池後面緊跟着就是訪問標誌,它的十六進制值爲0x0021,二進制的值爲:00000000 00100001,由二進制的1的位數能夠得出第十一、16位爲1,分別對應ACC_SUPER標誌位和ACC_PUBLIC標誌位。
也能夠經過一下運算:
0x0021 = 0x0001 | 0x0020, 即: 訪問標誌表示的標誌是ACC_PUBLIC + ACC_SUPER
爲了驗證咱們的運算,使用javap -v Simple查看反編譯信息以下:(小技巧:使用javap -v Simple指令的結果展現在命令提示符下顯示不友好,通常我是使用javap -v Simple > temp.txt,將結果重定向到文件中,而後查看文件)
類索引的做用,就是爲了指出class文件所描述的這個類叫什麼名字。
類索引緊接着訪問標誌的後面,佔有兩個字節,在這兩個字節中存儲的值是一個指向常量池的一個索引,該索引指向的是CONSTANT_Class_info常量池項,
以上面定義的Simple.class 爲例,以下圖所示,查看他的類索引在什麼位置和取什麼值。
由上可知,它的類索引值爲0x0001,那麼,它指向了常量池中的第一個常量池項,那咱們再看一下常量池中的信息。使用javap -v Simple,常量池中有如下信息:
能夠看到常量池中的第一項是CONSTANT_Class_info項,它表示一個"com/louis/jvm/Simple"的類名。即類索引是告訴咱們這個class文件所表示的是哪個類。
因爲類實現的接口數目不肯定,因此接口索引集合的描述的前部分叫作接口計數器(interfaces_count),接口計數器佔用兩個字節,其中的值表示着這個類實現了多少個接口,緊跟着接口計數器的部分就是接口索引部分了,每個接口索引佔有兩個字節,接口計數器的值表明着後面跟着的接口索引的個數。接口索引和類索引和父類索引同樣,其內的值存儲的是指向了常量池中的常量池項的索引,表示着這個接口的徹底限定名。
舉例:
定義一個Worker接口,而後類Programmer實現這個Worker接口,而後咱們觀察Programmer的接口索引集合是怎樣表示的。
-
/**
-
* Worker 接口類
-
* @author luan louis
-
*/
-
public
interface Worker{
-
-
public void work();
-
-
}
-
package com.louis.jvm;
-
-
public
class Programmer implements Worker {
-
-
@Override
-
public void work() {
-
System.out.println(
"I'm Programmer,Just coding....");
-
}
-
}