Static
Prerequisites:
靜態變數
在類別中,除了有成員變數之外,靜態變數也是類別的成員之一。
什麼是靜態變數?靜態變數指向metadata中一個儲存靜態變數「值」的記憶體位址,只儲存值,所有物件的靜態變數都指向同一個記憶體位址。
靜態變數的建立
靜態變數的Memory Model
- 在Heap中建立記憶體位址是0x0022的記憶體空間,Stack的s1變數指向0x0022。
- 建構子把靜態變數count++
- 把metadata中的儲存靜態變數的「值」+1。
- s1中的count屬性的記憶體位址是指向metadata中的儲存靜態值的位址0x0011。
- 在Heap中建立記憶體位址是0x0044的記憶體空間,Stack的s2變數指向0x0044。
- 建構子把靜態變數count++
- 把metadata中的儲存靜態變數的「值」+1。
- s2中的count屬性的記憶體位址是指向metadata中的儲存靜態值的位址0x0011。
由上圖知道,s1與s2的count屬性,指向的記憶體位址都是0x0011,共用同一個記憶體位址。
建立3個學生,並統計數量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Test {
public static void main(String[] args) {
Student s1 = new Student("Mary");
Student s2 = new Student("Bill");
Student s3 = new Student("Andy");
System.out.println(s1.getName() + ":" + s1.getCount());
System.out.println(s2.getName() + ":" + s2.getCount());
System.out.println(s3.getName() + ":" + s3.getCount());
}
}
class Student {
private String name;
private static int count;
public Student (String name) {
this.name = name;
count++;
}
public String getName() {
return name;
}
public int getCount() {
return count;
}
}
Mary:3
Bill:3
Andy:3
靜態變數使用方法
語法
類別名.靜態變數
物件.靜態變數
大部分都是使用「類別名.靜態變數」。
也可以使用「物件.靜態變數」,在Memory Model中,物件的靜態變數的記憶體位址,也是指向Mataspace中metadata靜態變數「值」的記憶體位址。
1
2
3
4
5
6
public class Test {
public static String static_name = "靜態變數";
public static void main(String[] args) {
System.out.println(Test.static_name);
}
}
靜態變數
靜態方法
語法
類別名.靜態方法()
靜態方法屬於類別的方法,只能存取靜態變數與靜態方法,通常作為工具類別,進行跟物件無關的操作。
1
2
3
4
5
6
7
8
public class Test {
public static void staticMethod1() {
System.out.println("靜態方法");
}
public static void main(String[] args) {
Test.staticMethod1();
}
}
靜態方法
靜態區塊
語法
1
2
3
static {
System.out.println("靜態區塊");
}
建構子的文章中,提到建立物件會先呼叫「匿名區塊」,才呼叫建構子。
那如果加上靜態區塊?誰先執行?答案是靜態區塊先執行,然後才是匿名區塊,最後是建構子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Test {
// 靜態區塊
static {
System.out.println("靜態區塊");
}
{
System.out.println("匿名區塊");
}
Test() {
System.out.println("建構子區塊");
}
public static void main(String[] args) {
Test test1 = new Test();
}
}
靜態區塊
匿名區塊
建構子區塊
靜態只產生一次
把前一個程式碼的main主程式改成下方,會發現靜態區塊只產生一次。
1
2
3
4
public static void main(String[] args) {
Test test1 = new Test();
Test test2 = new Test();
}
靜態區塊
匿名區塊
建構子區塊
匿名區塊
建構子區塊
由以上結果可知,執行2次new建立物件,但「靜態區塊」只會產生一次,不管建立多少次物件,靜態變數、靜態方法、靜態區塊,只會產生一次。
靜態方法只能存取靜態變數、靜態方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class StaticExample {
public static String static_name = "static_name";
public String name = "name";
public static void staticMethod1() {
System.out.println("呼叫靜態方法:");
staticMethod2();
System.out.println("印出靜態變數:" + static_name);
}
public static void staticMethod2() {
System.out.println("呼叫 staticMethod2()");
}
public static void main(String[] args) {
StaticExample.staticMethod1();
}
}
呼叫靜態方法:
呼叫 staticMethod2()
印出靜態變數:static_name
成員方法可以存取靜態變數、靜態方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class StaticExample {
public static String static_name = "static_name";
public String name = "name";
public static void staticMethod1() {
System.out.println("呼叫靜態方法:");
staticMethod2();
System.out.println("印出靜態變數:" + static_name);
}
public static void staticMethod2() {
System.out.println("呼叫 staticMethod2()");
}
public void method1() {
System.out.println("印出成員變數:" + name);
System.out.println("呼叫靜態方法:");
staticMethod2();
System.out.println("印出靜態變數:" + static_name);
}
public static void main(String[] args) {
StaticExample example = new StaticExample();
example.method1();
}
}
印出成員變數:name
呼叫靜態方法:
呼叫 staticMethod2()
印出靜態變數:static_name
main主程式也是靜態方法
main主程式也是靜態方法,可以直接存取類別的靜態方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class StaticExample {
public static String static_name = "static_name";
public String name = "name";
public static void staticMethod1() {
System.out.println("呼叫靜態方法:");
staticMethod2();
System.out.println("印出靜態變數:" + static_name);
}
public static void staticMethod2() {
System.out.println("呼叫 staticMethod2()");
}
public void method1() {
System.out.println("印出成員變數:" + name);
System.out.println("呼叫靜態方法:");
staticMethod2();
System.out.println("印出靜態變數:" + static_name);
}
public static void main(String[] args) {
staticMethod1();
}
}
呼叫靜態方法:
呼叫 staticMethod2()
印出靜態變數:static_name