方法區以及static的內存分配圖

前面的幾篇都沒有太明確地指出 方法區 是什麼?如今經過一些資料的收集和學習,下面作一些總結java

什麼是方法區:面試

 

方法區是系統分配的一個內存邏輯區域,是JVM在裝載類文件時,用於存儲類型信息的(類的描述信息)。app

 

方法區存放的信息包括:函數

類的基本信息:oop

1.每一個類的全限定名學習

2.每一個類的直接超類的全限定名(可約束類型轉換) this

3.該類是類仍是接口spa

4.該類型的訪問修飾符.net

5.直接超接口的全限定名的有序列表對象

已裝載類的詳細信息

1.      運行時常量池:在方法區中,每一個類型都對應一個常量池,存放該類型所用到的全部常量,常量池中存儲了諸如文字字符串、final變量值、類名和方法名常量。

2.      字段信息:字段信息存放類中聲明的每個字段的信息,包括字段的名、類型、修飾符。

3.      方法信息:類中聲明的每個方法的信息,包括方法名、返回值類型、參數類型、修飾符、異常、方法的字節碼。

(在編譯的時候,就已經將方法的局部變量、操做數棧大小等肯定並存放在字節碼中,在裝載的時候,隨着類一塊兒裝入方法區。) 

4.      靜態變量:類變量,類的全部實例都共享,咱們只需知道,在方法區有個靜態區,靜態區專門存放靜態變量和靜態塊。

5.      到類classloader的引用:到該類的類裝載器的引用。 

6.      到類class 的引用:虛擬機爲每個被裝載的類型建立一個class實例,用來表明這個被裝載的類。  

下面分析static的內存分配

 

[java]  view plain  copy
 print?
  1. public class Dome_Static {  
  2.   
  3.     public static void main(String[] args) {  
  4.         Person p1 = new Person();  
  5.         p1.name = "xiaoming";  
  6.         p1.country = "chinese";  
  7.         Person p2 = new Person();  
  8.         p2.name = "xiaohong";  
  9.         p1.speak();  
  10.         p2.speak();  
  11.     }  
  12.       
  13. }  
  14. class Person {  
  15.     String name;  
  16.     static String country;  
  17.     public void speak() {  
  18.         System.out.println("name:"+name+",country:"+country);  
  19.     }  
  20. }  

 

[java]  view plain  copy
 print?
  1. Output:  
  2. name:xiaoming,country:chinese  
  3. name:xiaohong,country:chinese  


1.首先,先加載Dome_Static,而後其main函數入棧,以後Person被加載。static聲明的變量會隨着類的加載而加載,因此在內存中只會存在一份,實例化多個對象,都共享同一個static變量,會默認初始化

 

2.在棧內存爲 p1 變量申請一個空間,在堆內存爲Person對象申請空間,初始化完畢後將其地址值返回給p1,經過p1.name和p1.country修改其值

3.在棧內存爲 p2 變量申請一個空間,在堆內存爲Person對象申請空間,初始化完畢後將其地址值返回給p2,僅僅經過p2.name修改其值

4.打印show方法,進棧,這裏就不畫圖了,對於棧相關的概念不清楚的能夠看看在以前發的博客。簡單口述下:p1.show()  show方法入棧,在方法的內部有個指向堆內存的this引用,經過該引用可找到堆內存實體,打印country時,可經過該堆內存對象找到對應的類,讀取對應靜態區中的字段值

 

最後給你們一道面試題練練手,要求寫出其結果(筆試)

 

[java]  view plain  copy
 print?
  1. public class StaticTest {  
  2.       
  3.     public static int k = 0;  
  4.     public static StaticTest t1 = new StaticTest("t1");  
  5.     public static StaticTest t2 = new StaticTest("t2");  
  6.     public static int i = print("i");  
  7.     public static int n = 99;  
  8.     public int j = print("j");  
  9.        
  10.     {  
  11.         print("構造塊");  
  12.     }  
  13.        
  14.     static{  
  15.         print("靜態塊");  
  16.     }  
  17.        
  18.     public StaticTest(String str) {  
  19.         System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);  
  20.         ++n;  
  21.         ++i;  
  22.     }  
  23.        
  24.     public static int print(String str) {  
  25.         System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);  
  26.         ++i;  
  27.         return ++n;  
  28.     }  
  29.     public static void main(String[] args) {  
  30.         StaticTest t = new StaticTest("init");  
  31.     }  
  32.    
  33. }  


結果:

 

 

[java]  view plain  copy
 print?
  1. 1:j i=0 n=0  
  2. 2:構造塊 i=1 n=1  
  3. 3:t1 i=2 n=2  
  4. 4:j i=3 n=3  
  5. 5:構造塊 i=4 n=4  
  6. 6:t2 i=5 n=5  
  7. 7:i i=6 n=6  
  8. 8:靜態塊 i=7 n=99  
  9. 9:j i=8 n=100  
  10. 10:構造塊 i=9 n=101  
  11. 11:init i=10 n=102  


這個留給你們去思考,若是一眼便能便知道爲何是這樣的輸出結果,那麼靜態方面知識應該比較紮實了

 

提示一下 :

1.加載的順序:先父類的static成員變量 -> 子類的static成員變量 -> 父類的成員變量 -> 父類構造 -> 子類成員變量 -> 子類構造

2.static只會加載一次,因此通俗點講第一次new的時候,全部的static都先會被所有載入(之後再有new都會忽略),進行默認初始化。在從上往下進行顯示初始化。這裏靜態代碼塊和靜態成員變量沒有前後之分,誰在上,誰就先初始化

3.構造代碼塊是什麼?把全部構造方法中相同的內容抽取出來,定義到構造代碼塊中,未來在調用構造方法的時候,會去自動調用構造代碼塊。構造代碼快優先於構造方法。

相關文章
相關標籤/搜索