最近一直被方法區里面存着什么東西困擾着?
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文件是下面這樣的 javap -v -verbose xxx.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