static是Java中的一個關鍵字,用來修飾成員變量與成員方法,還可以用於編寫靜態代碼塊,對於被static修飾的東西,JVM在加載類的時候,就給這些變量在內存中分配了一定的空間,即在編譯階段時就為這些成員變量的實例分配了空間。
一、靜態變量
被static關鍵字修飾的成員變量叫做靜態變量,前面我們講到成員變量與局部變量的區別,那麼靜態變量與成員變量又有哪些不同呢?
1、調用方式
靜態變量:類變量,可以直接通過類名調用,也可以通過對象名調用,這個變量屬於類
成員變量:實例變量,只能通過對象名調用,這個變量屬於對象
2、存儲位置
靜態變量:存儲在方法區中的靜態區
成員變量:存儲在堆內存
3、生命周期
靜態變量:隨著類的加載而存在,隨著類的消失而消失
成員變量:隨著對象的創建而存在,隨著對象的消失而消失
4、與對象的相關性
靜態變量:所有對象共享的數據,在內存中只有一個副本
成員變量:每個對象所特有的數據,在內存中存在多個副本,每個副本之間互不影響
看了以上幾點,我們會想那什麼時候使用static來修飾我們的變量呢,從第4點可以看出當所定義的變量是所有的實例所共享的數據的時候,我們就可以用static來修飾,例如,我們每個人都有國籍,通常情況下國籍都是中國,那麼這個時候就可以用static來修飾了
1 package demo; 2 3 public class Person { 4 private String name; 5 private int age; 6 private static String nationality = "中國"; 7 8 .... 9 }
這樣當構造Person類的時候就不用每次都給nationality這個屬性分配內存空間,這時在內存中就只有一個副本,每個實例對象都指向它,當其中一個改變了nationality變量的值,則其他對象的nationality值也隨著改變。
二、靜態方法
被static關鍵字修飾的成員方法叫做靜態方法,看看我們最常見的main方法
1 package demo; 2 3 public class MainDemo { 4 public static void main(String[] args) { 5 System.out.println("main method"); 6 } 7 }
此時代碼中並沒有構造一個MainDemo對象,但是運行程序卻在控制台打印出了main method,這個例子可以說明靜態方法優於對象而存在,與靜態變量一樣,在類加載時就存在了,那麼,如果我們在靜態方法中調用非靜態變量與非靜態方法會有什麼現象呢,看下面這段代碼
1 package demo; 2 3 public class MainDemo { 4 private String name; 5 private static String address; 6 7 public static void main(String[] args) { 8 show1(); // Cannot make a static reference to the non-static method 9 // show1() from the type MainDemo 10 show2(); 11 } 12 13 private void show1() { 14 System.out.println(name); 15 System.out.println(address); 16 } 17 18 private static void show2() { 19 System.out.println(name); // Cannot make a static reference to the 20 // non-static field name 21 System.out.println(address); 22 } 23 }
代碼中第8行與第19行報錯,報錯信息在代碼右側已經注釋出來,由於靜態方法在類加載的時候就已經在內存中了,此時對象還不存在,故在靜態方法中無法訪問非靜態變量,非靜態變量在創建對象的時候才會在堆空間中存在,一個不存在的東西又怎麼能訪問呢,同樣在靜態方法中無法訪問非靜態方法的原因與之一樣。既然非靜態方法為所有實例所共享,那麼該方法也為類所有,那自然可以通過類名調用
1 package demo; 2 3 public class MainDemo { 4 private static String address; 5 6 public static void main(String[] args) { 7 MainDemo.show(); 8 } 9 10 private static void show() { 11 System.out.println(address); 12 } 13 }
三、靜態代碼塊
static塊可以置於類中的任何地方,類中可以有多個static塊。與成員變量,成員方法一樣,在類被加載的時候靜態代碼塊就存在於內存中了,在類初次加載的時候,JVM按照static塊的順序來執行每個static塊,並且只會執行一次,這樣無形中也提高了點性能。
1 package demo; 2 3 public class StaticDemo { 4 private static String address = "china"; 5 6 static { 7 System.out.println("first static block"); 8 } 9 10 static { 11 System.out.println("second static block"); 12 } 13 14 public static void main(String[] args) { 15 StaticDemo.show(); 16 } 17 18 private static void show() { 19 System.out.println(address); 20 } 21 }
輸出結果:
first static block second static block china
從以上我們總結出以下static關鍵字的一些特性:
1、靜態可以用來修飾成員變量,成員方法,靜態代碼塊;
2、隨著類的加載而加載,優先於對象而存在,被所有的對象所共享,可以被類名直接調用(建議),當然也通過實例調用,雖然在內存中的副本只有一個,不過生命周期長,當類被回收時,靜態區域空間才會被釋放;
3、靜態方法中只能訪問靜態變量與靜態成員;
4、當所有對象共享某個數據的時候,就把這個成員變量定義為靜態的;
5、靜態代碼塊只執行一次。