通常情況下,Java把內存分為棧內存、堆內存和方法區,棧內存用來存放一些基本類型的變量和數組(數組也是一種引用類型)及對象的引用變量,而堆內存主要是來放置對象的,即我們在程序中new出來的對象。static,意味為靜態的,用static修飾的變量和方法,實際上是給這些變量和方法指定了在內存中的”位置“(這個位置也叫靜態區、方法區、數據區和共享區)。既然在內存中指定了位置,那麼他們的 “大小”似乎就是固定的了,有了位置和大小的特征,在棧中或堆中開辟空間那就是非常的方便了。對於靜態的東西,JVM在加載類時,就在內存中開辟了這些靜態變量的空間(內存空間),即編譯時就為這些成員變量的實例分配了空間。
下面我們來看一段代碼
1 package demo; 2 3 public class StaticDemo { 4 public static void main(String[] args) { 5 Visitor visitor1 = new Visitor(); 6 System.out.println("count : " + visitor1.count);// 1 7 System.out.println("visitCount : " + Visitor.visitCount);// 1 8 9 Visitor visitor2 = new Visitor(); 10 System.out.println("count : " + visitor2.count);// 1 11 System.out.println("visitCount : " + Visitor.visitCount);// 2 12 13 Visitor visitor3 = new Visitor(); 14 visitor3.count = 5; 15 visitor3.visitCount = 0; // 歸0 16 System.out.println("count : " + visitor1.count);// 1 17 System.out.println("count : " + visitor2.count);// 1 18 System.out.println("count : " + visitor3.count);// 5 19 System.out.println("visitCount : " + visitor1.visitCount);// 0 20 System.out.println("visitCount : " + visitor2.visitCount);// 0 21 System.out.println("visitCount : " + visitor3.visitCount);// 0 22 } 23 } 24 25 class Visitor { 26 int count; 27 static int visitCount; 28 29 public Visitor() { 30 count++; 31 visitCount++; 32 } 33 }
從上面代碼來看,用static修飾的變量,每個類的實例改變的都是同一個副本,即在內存中static修飾的變量只有一份,而沒有普通的成員變量,每個實例都有各自的副本,我們用圖來簡單的分析StaticDemo類的代碼,首先JVM把Visit類與StaticDemo類編譯完然後加載到方法區,在Visit方法區中,JVM檢查到有個static修飾的變量visitCount,則又開辟了一塊內存(叫做靜態區)來存放,此時內存情況
接著JVM會自動尋找main方法並在棧中為其開辟一個空間,再看代碼第5行,這時,來了一個訪問者visitor1,JVM在棧中為visitor1開辟了一塊內存,並且指向堆中的Visitor內存空間,由於count與visitCount為成員變量,所以有默認初始值0,根據代碼第6行跟第7行的運行結果,我們可以得到count與visitCount變量在堆內存中的值
同理9,10,11行與5,6,7行分析類似,此時內存情況及count與visitCount變量的值
接下來來了一個visitor3,把count與visitCount都重新賦值了
由於visitor1,visitor2,visitor3在堆空間中都有各自的count變量,所有當visitor3改變了count變量的值時,visitor1與visitor2的count變量值並沒有受影響,而當visitor3堆visitCount重新賦值了,因為visitor1,visitor2,visitor3的visitCount都為靜態區中的0x0001,所以用visitor1,visitor2,visitor3訪問的visitCount為最新的值0。可見,靜態變量與具體的實例無關,屬於整個類,在編程中,當所有對象共享某個數據的時候,我們就可以把這個成員變量定義為靜態的,如上面的visitCount。