《Java虛擬機原理圖解》四、class文件中的訪問標誌、類索引、父類索引、接口索引集合--轉載

      講完了class文件中的常量池,咱們就至關於克服了class文件中最麻煩的模塊了。如今,咱們來看一下class文件中緊接着常量池後面的幾個東西:訪問標誌、類索引、父類索引、接口索引集合。html

1. 訪問標誌、類索引、父類索引、接口索引集合 在class文件中的位置

         好,讓咱們來一一擊破它們,看看它們究竟是什麼東西。java

2. 訪問標誌(access_flags)可以表示什麼?

    訪問標誌(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標誌位
lua

 b. class文件表示的類或者接口的訪問權限有public類型的和包package類型的。spa

      若是類或者接口被聲明爲public類型的,那麼,JVM將其編譯成class文件時,會將class文件的訪問標誌的第16位設置爲1 。第16位叫作ACC_PUBLIC標誌符
.net

 c. 類是否爲抽象類型的,即咱們定義的類有沒有被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 查看訪問標誌。

   
   
   
   
   
  1. package com.louis.jvm;
  2. public class Simple {
  3. }
使用UltraEdit查看編譯成的class文件,以下圖所示:

上述的圖中黃色部分表示的是常量池部分,具體爲何是常量池部分不是本文的重點,有興趣的讀者能夠參考個人《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,將結果重定向到文件中,而後查看文件)


 

3. 類索引(this_class)是什麼?

            咱們知道通常狀況下一個Java類源文件通過JVM編譯會生成一個class文件,也有可能一個Java類源文件中定義了其餘類或者內部類,這樣編譯出來的class文件就不止一個,但每個class文件表示某一個類,至於這個class表示哪個類,即可以經過 類索引 這個數據項來肯定。JVM經過類的徹底限定名肯定是某一個類。

        類索引的做用,就是爲了指出class文件所描述的這個類叫什麼名字。

        類索引緊接着訪問標誌的後面,佔有兩個字節,在這兩個字節中存儲的值是一個指向常量池的一個索引,該索引指向的是CONSTANT_Class_info常量池項,

         

         以上面定義的Simple.class 爲例,以下圖所示,查看他的類索引在什麼位置和取什麼值。

         

           由上可知,它的類索引值爲0x0001,那麼,它指向了常量池中的第一個常量池項,那咱們再看一下常量池中的信息。使用javap -v Simple,常量池中有如下信息:

        

            能夠看到常量池中的第一項是CONSTANT_Class_info項,它表示一個"com/louis/jvm/Simple"的類名。即類索引是告訴咱們這個class文件所表示的是哪個類。


3. 父類索引(super_class)是什麼?

    Java支持單繼承模式,除了java.lang.Object 類除外,每個類都會有且只有一個父類。class文件中緊接着類索引(this_class)以後的兩個字節區域表示父類索引,跟類索引同樣,父類索引這兩個字節中的值指向了常量池中的某個常量池項CONSTANT_Class_info,表示該class表示的類是繼承自哪個類。


4. 接口索引集合(interfaces)是什麼?

      一個類能夠不實現任何接口,也能夠實現不少個接口,爲了表示當前類實現的接口信息,class文件使用了以下結構體描述某個類的接口實現信息:

   因爲類實現的接口數目不肯定,因此接口索引集合的描述的前部分叫作接口計數器(interfaces_count)接口計數器佔用兩個字節,其中的值表示着這個類實現了多少個接口,緊跟着接口計數器的部分就是接口索引部分了,每個接口索引佔有兩個字節,接口計數器的值表明着後面跟着的接口索引的個數。接口索引和類索引和父類索引同樣,其內的值存儲的是指向了常量池中的常量池項的索引,表示着這個接口的徹底限定名。


舉例:

      定義一個Worker接口,而後類Programmer實現這個Worker接口,而後咱們觀察Programmer的接口索引集合是怎樣表示的。

      

  
  
  
  
  
  1. /**
  2. * Worker 接口類
  3. * @author luan louis
  4. */
  5. public interface Worker{
  6. public void work();
  7. }
  
  
  
  
  
  1. package com.louis.jvm;
  2. public class Programmer implements Worker {
  3. @Override
  4. public void work() {
  5. System.out.println( "I'm Programmer,Just coding....");
  6. }
  7. }


本文源自  http://blog.csdn.net/luanlouis/
相關文章
相關標籤/搜索