方法區和常量池
最近一直被方法區裡面存著什麼東西困擾著?
1.方法區裡存class檔案資訊和class檔案常量池是個什麼關係。
2.class檔案常量池和執行時常量池是什麼關係。
方法區存著類的資訊,常量和靜態變數,即類被編譯後的資料。這個說法其實是沒問題的,只是太籠統了。更加詳細一點的說法是方法區裡存放著類的版本,欄位,方法,介面和常量池。常量池裡儲存著字面量和符號引用。
符號引用包括:1.類的全限定名,2.欄位名和屬性,3.方法名和屬性。
下面一張圖是我畫的方法區,class檔案資訊,class檔案常量池和執行時常量池的關係
下面一張圖用來表示方法區class檔案資訊包括哪些內容:
可以看到在方法區裡的class檔案資訊包括:魔數,版本號,常量池,類,父類和介面陣列,欄位,方法等資訊,其實類裡面又包括欄位和方法的資訊。
下面的圖表是class檔案中儲存的資料型別
型別 | 名稱 | 數量 |
u4 | magic | 1 |
u2 | minor_version | 1 |
u2 | major_version | 1 |
u2 | constant_pool_count | 1 |
cp_info | constant_pool | constant_pool_count - 1 |
u2 | access_flags | 1 |
u2 | this_class | 1 |
u2 | super_class | 1 |
u2 | interfaces_count | 1 |
u2 | interfaces | interfaces_count |
u2 | fields_count | 1 |
field_info | fields | fields_count |
u2 | methods_count | 1 |
method_info | methods | methods_count |
u2 | attribute_count | 1 |
attribute_info | attributes | attributes_count |
下面用一張圖來表示常量池裡儲存的內容:
用一個class檔案實際反編譯一下
下面是原java程式碼
public class TestInt {
private String str = "hello";
void printInt(){
System.out.println(65535);
}
}
經過反編譯後獲得class檔案是下面這樣的
可以看出被反編譯的class檔案中的內容和上面所說的是能對應上的。這就解答了class檔案和靜態常量池(class檔案常量池)的關係
靜態常量池和動態常量池的關係以及區別
靜態常量池儲存的是當class檔案被java虛擬機器載入進來後存放在方法區的一些字面量和符號引用,字面量包括字串,基本型別的常量,符號引用其實引用的就是常量池裡面的字串,但符號引用不是直接儲存字串,而是儲存字串在常量池裡的索引。
動態常量池是當class檔案被載入完成後,java虛擬機器會將靜態常量池裡的內容轉移到動態常量池裡,在靜態常量池的符號引用有一部分是會被轉變為直接引用的,比如說類的靜態方法或私有方法,例項構造方法,父類方法,這是因為這些方法不能被重寫其他版本,所以能在載入的時候就可以將符號引用轉變為直接引用,而其他的一些方法是在這個方法被第一次呼叫的時候才會將符號引用轉變為直接引用的。
總結:
方法區裡儲存著class檔案的資訊和動態常量池,class檔案的資訊包括類資訊和靜態常量池。可以將類的資訊是對class檔案內容的一個框架,裡面具體的內容通過常量池來儲存。
動態常量池裡的內容除了是靜態常量池裡的內容外,還將靜態常量池裡的符號引用轉變為直接引用,而且動態常量池裡的內容是能動態新增的。例如呼叫String的intern方法就能將string的值新增到String常量池中,這裡String常量池是包含在動態常量池裡的,但在jdk1.8後,將String常量池放到了堆中。
下面有一篇文章寫的是比較好的
http://blog.csdn.net/vegetable_bird_001/article/details/51278339
https://www.cnblogs.com/holos/p/6603379.html