在一個
class
中定義的字段,我們稱之爲實例字段。實例字段的特點是,每個實例都有獨立的字段,各個實例的同名字段互不影響。
還有一種字段,是用
static
修飾的字段,稱爲靜態字段:static field
。
實例字段在每個實例中都有自己的一個獨立“空間”,但是靜態字段只有一個共享“空間”,所有實例都會共享該字段。舉個例子:
class Person {
public String name;
public int age;
// 定義靜態字段number:
public static int number;
}
我們來看看下面的代碼:
public class Main {
public static void main(String[] args) {
Person ming = new Person("Xiao Ming", 12);
Person hong = new Person("Xiao Hong", 15);
ming.number = 88;
System.out.println(hong.number);
hong.number = 99;
System.out.println(ming.number);
}
}
class Person {
public String name;
public int age;
public static int number;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
結果:
88
99
對於靜態字段,無論修改哪個實例的靜態字段,效果都是一樣的:所有實例的靜態字段都被修改了,原因是靜態字段並不屬於實例:
┌──────────────────┐
ming ──>│Person instance │
├──────────────────┤
│name = "Xiao Ming"│
│age = 12 │
│number ───────────┼──┐ ┌─────────────┐
└──────────────────┘ │ │Person class │
│ ├─────────────┤
├───>│number = 99 │
┌──────────────────┐ │ └─────────────┘
hong ──>│Person instance │ │
├──────────────────┤ │
│name = "Xiao Hong"│ │
│age = 15 │ │
│number ───────────┼──┘
└──────────────────┘
雖然實例可以訪問靜態字段,但是它們指向的其實都是Person class
的靜態字段。所以,所有實例共享一個靜態字段。
因此,不推薦用實例變量.靜態字段
去訪問靜態字段,因爲在Java程序中,實例對象並沒有靜態字段。在代碼中,實例對象能訪問靜態字段只是因爲編譯器可以根據實例類型自動轉換爲類名.靜態字段
來訪問靜態對象。
推薦用類名來訪問靜態字段。可以把靜態字段理解爲描述class
本身的字段(非實例字段)。對於上面的代碼,更好的寫法是:
Person.number = 99;
System.out.println(Person.number);
靜態方法
有靜態字段,就有靜態方法。用static
修飾的方法稱爲靜態方法。
調用實例方法必須通過一個實例變量,而調用靜態方法則不需要實例變量,通過類名就可以調用。靜態方法類似其它編程語言的函數。例如:
public class Main {
public static void main(String[] args) {
Person.setNumber(99);
System.out.println(Person.number);
}
}
class Person {
public static int number;
public static void setNumber(int value) {
number = value;
}
}
結果:
99
因爲靜態方法屬於class
而不屬於實例,因此,靜態方法內部,無法訪問this
變量,也無法訪問實例字段,它只能訪問靜態字段。
通過實例變量也可以調用靜態方法,但這只是編譯器自動幫我們把實例改寫成類名而已。
通常情況下,通過實例變量訪問靜態字段和靜態方法,會得到一個編譯警告。
靜態方法經常用於工具類。例如:
-
Arrays.sort()
-
Math.random()
靜態方法也經常用於輔助方法。注意到Java程序的入口main()
也是靜態方法。
接口的靜態字段
因爲interface
是一個純抽象類,所以它不能定義實例字段。但是,interface
是可以有靜態字段的,並且靜態字段必須爲final
類型:
public interface Person {
public static final int MALE = 1;
public static final int FEMALE = 2;
}
實際上,因爲interface
的字段只能是public static final
類型,所以我們可以把這些修飾符都去掉,上述代碼可以簡寫爲:
public interface Person {
// 編譯器會自動加上public statc final:
int MALE = 1;
int FEMALE = 2;
}
編譯器會自動把該字段變爲public static final
類型。