通常,我們創建類時會指出那個類的對象的外觀與行為。除非用new創建那個類的一個對象,否則實際上並未得到任何東西。只有執行了new後,才會正式生成數據存儲空間,並可使用相應的方法。
但在兩種特殊的情形下,上述方法並不堪用。一種情形是只想用一個存儲區域來保存一個特定的數據——無論要創建多少個對象,甚至根本不創建對象。另一種情形是我們需要一個特殊的方法,它沒有與這個類的任何對象關聯。也就是說,即使沒有創建對象,也需要一個能調用的方法。為滿足這兩方面的要求,可使用static(靜態)關鍵字。一旦將什麼東西設為static,數據或方法就不會同那個類的任何對象實例聯系到一起。所以盡管從未創建那個類的一個對象,仍能調用一個static方法,或訪問一些static數據。而在這之前,對於非static數據和方法,我們必須創建一個對象,並用那個對象訪問數據或方法。這是由於非static數據和方法必須知道它們操作的具體對象。當然,在正式使用前,由於static方法不需要創建任何對象,所以它們不可簡單地調用其他那些成員,同時不引用一個已命名的對象,從而直接訪問非static成員或方法(因為非static成員和方法必須同一個特定的對象關聯到一起)。
有些面向對象的語言使用了“類數據”和“類方法”這兩個術語。它們意味著數據和方法只是為作為一個整體的類而存在的,並不是為那個類的任何特定對象。有時,您會在其他一些Java書刊裡發現這樣的稱呼。
為了將數據成員或方法設為static,只需在定義前置和這個關鍵字即可。例如,下述代碼能生成一個static數據成員,並對其初始化:
class StaticTest {
Static int i = 47;
}
現在,盡管我們制作了兩個StaticTest對象,但它們仍然只占據StaticTest.i的一個存儲空間。這兩個對象都共享同樣的i。請考察下述代碼:
StaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
此時,無論st1.i還是st2.i都有同樣的值47,因為它們引用的是同樣的內存區域。
有兩個辦法可引用一個static變量。正如上面展示的那樣,可通過一個對象命名它,如st2.i。亦可直接用它的類名引用,而這在非靜態成員裡是行不通的(最好用這個辦法引用static變量,因為它強調了那個變量的“靜態”本質)。
StaticTest.i++;
其中,++運算符會使變量增值。此時,無論st1.i還是st2.i的值都是48。
類似的邏輯也適用於靜態方法。既可象對其他任何方法那樣通過一個對象引用靜態方法,亦可用特殊的語法格式“類名.方法()”加以引用。靜態方法的定義是類似的:
class StaticFun {
static void incr() { StaticTest.i++; }
}
從中可看出,StaticFun的方法incr()使靜態數據i增值。通過對象,可用典型的方法調用incr():
StaticFun sf = new StaticFun();
sf.incr();
或者,由於incr()是一種靜態方法,所以可通過它的類直接調用:
StaticFun.incr();
盡管是“靜態”的,但只要應用於一個數據成員,就會明確改變數據的創建方式(一個類一個成員,以及每個對象一個非靜態成員)。若應用於一個方法,就沒有那麼戲劇化了。對方法來說,static一項重要的用途就是幫助我們在不必創建對象的前提下調用那個方法。正如以後會看到的那樣,這一點是至關重要的——特別是在定義程序運行入口方法main()的時候。
和其他任何方法一樣,static方法也能創建自己類型的命名對象。所以經常把static方法作為一個“領頭羊”使用,用它生成一系列自己類型的“實例”。