1. 程式人生 > >jvm06、常量池和引用

jvm06、常量池和引用

在學習java的時候,我們經常會遇到一些很相似的概念,這個簡單來說就是名字很相似,比如我們之前提到的物件和物件引用,還有今天我們要說到的

  1. 符號引用
  2. 直接引用
  3. class檔案常量池
  4. 執行時常量池
  5. 字串常量池

有的人可能會覺得幹嘛花費時間精力在這塊,感覺有點摳字眼了,我想說的是,這絕對不是摳字眼,弄清楚這些概念,對以後的學習很重要,而且我們這個專題準備好好的說一說這個java虛擬機器,這些概念,對於虛擬機器的學習

很重要!!!

首先,我們來看下面一段敘述:

當我們完成一個java檔案的編寫,然後經過javac命令的編譯成了class檔案,這個class檔案除了有類的版本,方法,欄位和介面等資訊以外,還有一項重要的資訊就是常量池,這個叫做class檔案常量池,主要就是用來存放

  1. 編譯期生成的各種字面值
    1. 文字字串
    2. 八種基本資料型別的值
    3. 被宣告為final的常量等
  2. 符號引用
    1. 類和方法的全限定名
    2. 欄位的名稱和描述符
    3. 方法的名稱和描述符

當類從java檔案編譯成class檔案,這個時候就有了class檔案常量池,當被載入到記憶體中的時候class檔案常量池也被載入進去了,這個時候class檔案常量池就變成了執行時常量池,此時可以動態的新增字面量,符號引用也可以被解析為直接引用。

當一個執行緒開始的時候就產生了一個java虛擬機器棧,當執行緒中的一個方法被呼叫的時候就會產生一個棧幀,這個棧幀就開始入棧(java虛擬機器棧),這個棧幀中有一個區域性變量表,用來存放基本資料型別和物件引用,例項物件存放在堆中,但是物件引用在區域性變量表中,此物件引用指向堆中的具體物件。

(如果上面有說得不對的地方,煩請指出!謝過!)

在上面這段描述中出現了這麼幾個概念

  1. Class檔案常量池
  2. 執行時常量池
  3. 符號引用
  4. 直接引用

我們這裡再加上一個字串常量池,也就是這次我們一定要弄清楚這幾個概念

常量池:

  1. Class檔案常量池
  2. 執行時常量池
  3. 字串常量池

引用:

  1. 符號引用
  2. 直接引用

首先,我們來說說這個Class檔案常量池,我們編寫的java檔案會被編譯為class檔案,這個class檔案除了有類的版本,方法,欄位和介面等資訊以外,還有一項重要的資訊就是常量池,這個叫做class檔案常量池,主要就是用來存放

  1. 編譯期生成的各種字面值
    1. 文字字串
    2. 八種基本資料型別的值
    3. 被宣告為final的常量等
  2. 符號引用
    1. 類和方法的全限定名
    2. 欄位的名稱和描述符
    3. 方法的名稱和描述符
      也就是說,我們的java原始檔生成的class檔案中包含一個常量池,叫做class檔案常量池,這裡注意一點的就是這個時候只是從java原始檔編譯成class檔案,然後其中產生一個class檔案常量池,注意還沒有載入到記憶體。

那什麼是執行時常量池呢?

經過上一步驟,java原始檔被編譯成class檔案,其中有一個class檔案常量池,然後這些會別加載到記憶體中,也就是jvm的執行時資料區,也就是我們之前說的餓那幾個記憶體區域,這塊可以看看之前說的jvm記憶體結構,當被載入到記憶體中的時候,這個時候會有一個執行時常量池,那麼這個執行時常量池是怎麼來的呢?其實它就是之前的class檔案常量池演變過來的,當然這個執行時常量池還包含一些其他內容。

可以這麼說,這個執行時常量池是在被載入到記憶體之後,而class檔案常量池並未涉及記憶體,還在記憶體之外!而此時的執行時常量池可以動態的新增字面量,符號引用也可以被解析為直接引用。

至於字串常量池,應該是大家最為熟悉的一個了,我們要記住的一個知識點就是字串常量池的位置,在jdk1.7以前是存放在方法區中的,但是在jdk1.7及之後就被放在了堆中。

下面我們再來說說引用,

可能我們之前一直在說引用引用,並沒有細分到符號引用和物件引用,那麼現在我們就來學習這兩個概念,讓我們對引用有個新的認識。

那什麼是符號引用呢?

要想知道什麼是符號引用,你必須知道的一個前提就是這裡的符號引用強調的是在java原始檔編譯成class檔案之後,這個時候你要知道其實一個類的引用並不能確定到底指向的是誰,因此只能使用特定的符號代替,這就叫做符號引用,比如在Class檔案中它以CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等型別的常量出現。

我們在上面說過在執行時常量池那個階段就可以將符號引用解析成直接引用,所以,所謂的直接引用是在類載入階段,也就是在記憶體中了,經過解析會從符號引用解析成直接引用,也就成了一個指向具體目標的記憶體地址!

對了,還有一個物件引用,這個,你知道的!

測試