最近在熟悉項目代碼時,看到了關於static的新用法,網上查找重新學習了一下關於static的用法,看到一篇好文章,記錄下
https://www.dazhuanlan.com/2020/03/26/5e7cb77177083/
上一章說到了static關鍵字,static是Java中很重要的一個關鍵字,在一些場景下可以達到優化程序的效果。本文學習它的不同使用場景。在此之前先了解一下變量的類型。Java中變量分為兩種,按作用域分為成員變量和局部變量。成員變量是在類中聲明的,不屬於任何方法,當前類中有效。局部變量是聲明在方法中的,出了當前方法即超出作用域。接下來正文說一下static關鍵字的四中使用場景:
static最常用的作用就是修飾成員變量,被static修飾的成員變量也叫做類變量。它與普通成員變量的區別是,它在內存中只有一份拷貝,Java虛擬機只為其分配一次內存。通俗的講就是,這個變量,不管被多少人使用,他們使用的都是同一個變量,彼此的修改會有影響。可以通過類名.變量的形式進行訪問。而普通的成員變量則是沒實例化一個對象就產生一個拷貝,虛擬機為每一個變量拷貝都分配了內存。所以類變量的用處一般在於進行變量共享的時候。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public class { private String name; private int age; public void print(){ System.out.println("Name:" + name + "---Age:" + age); } public static void main(String[] args) { TestStatic ts1 = new TestStatic(); TestStatic ts2 = new TestStatic(); ts1.name = "zhangsan"; ts1.age = 22; ts2.name = "lisi"; ts2.age = 33; ts1.print(); ts2.print(); } }
|
這是普通的成員變量的例子,ts1和ts2對於變量name和age分別擁有自己的副本,互相不影響,所以賦值之后,他們能得到他們期望的值。

接下來將成員變量age修改為類變量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public class { private String name; private static int age; public void print(){ System.out.println("Name:" + name + "---Age:" + age); } public static void main(String[] args) { TestStatic ts1 = new TestStatic(); TestStatic ts2 = new TestStatic(); ts1.name = "zhangsan"; ts1.age = 22; ts2.name = "lisi"; ts2.age = 33; ts1.print(); ts2.print(); } }
|
這時由於age變成了類變量,因此ts1和ts2共用了一個變量副本,先賦值的會被后賦值的覆蓋掉。

此外第二個示例代碼中,靜態成員變量使用了對象.變量的方式進行調用,這里編譯器會給出警告,使用類名.方法之后警告就會解除。

二、修飾成員方法
static另一個作用是修飾類中的方法,其目的是可以通過類名.方法的形式調用方法,而避免頻繁的創建對象。同時對於存儲空間來說也只有一個,不同對象調用的是同一個方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public class { private String name; private static int age; public static void print(){ System.out.println("Name:" + name + "---Age:" + age); } public static void main(String[] args) { TestStatic ts1 = new TestStatic(); TestStatic ts2 = new TestStatic(); ts1.name = "zhangsan"; ts1.age = 22; ts2.name = "lisi"; TestStatic.age = 33; TestStatic.print(); TestStatic.print(); } }
|
將之前代碼中的print方法改為使用static修飾之后,這個方法就可以不用對象.方法的形式調用了。
三、修飾代碼塊
我們先看一下對象的初始化過程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
class Load { public Load(String msg){ System.out.println(msg); } } public class { Load ld1 = new Load("普通變量1"); Load ld2 = new Load("普通變量2"); static Load ld3 = new Load("靜態變量3"); static Load ld4 = new Load("靜態變量4"); public (String msg){ System.out.println(msg); } public static void main(String[] args) { TestStatic ts = new TestStatic("TestStatic 初始化"); } }
|
在類TestStatic中,我們初始化了兩個普通成員變量和兩個靜態成員變量,並在main函數開始的時候初始化了TestStatic對象。結果如下:

靜態成員變量最先被初始化,並且按照執行的先后順序進行初始化。其次初始化的是成員變量,最后初始化的是構造方法。所以在創建一個對象的時候,最先被初始化的是靜態成員變量。
在看另外一個調用了靜態方法的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
class Load { public Load(String msg){ System.out.println(msg); } } public class TestStatic{ Load ld1 = new Load("普通變量1"); Load ld2 = new Load("普通變量2"); static Load ld3 = new Load("靜態變量3"); static Load ld4 = new Load("靜態變量4"); public TestStatic(String msg){ System.out.println(msg); } public static void staticFunc(){ System.out.println("靜態方法"); } public static void main(String[] args) { TestStatic.staticFunc(); System.out.println("@@@@@@@@@"); TestStatic ts = new TestStatic("TestStatic 初始化"); } }
|
我們在創建對象之前先調用了靜態方法,結果如下:

我們可以看到,靜態成員的初始化發生在創建對象之前,確切的說是在調用靜態方法之前就已經被初始化了。並且,當我們創建對象的時候,原本被初始化過的靜態成員變量跟靜態方法沒有再次被初始化。
這時我們的static的作用就是,修飾一段都需要被修飾為static的域。被static修飾的代碼域,域中所有的內容都被當成static變量,且優先初始化。
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 27
|
class Load { public Load(String msg){ System.out.println(msg); } } public class TestStatic{ Load ld1 = new Load("普通變量1"); Load ld2 = new Load("普通變量2"); static Load ld3; static Load ld4; static{ ld3 = new Load("靜態變量3"); ld4 = new Load("靜態變量4"); } public TestStatic(String msg){ System.out.println(msg); } public static void staticFunc(){ System.out.println("靜態方法"); } public static void main(String[] args) { TestStatic.staticFunc(); System.out.println("@@@@@@@@@"); TestStatic ts = new TestStatic("TestStatic 初始化"); } }
|
修改之前的代碼將靜態成員變量放在由static修飾的域中,結果如下:

與分開修飾結果相同。
四、靜態導入
前邊三種都是比較常用的場景,還有一種不是太常用,是JDK1.5之后新加入的功能,導入一個帶有靜態方法的包,並將包修飾為static,從而在當前類中直接調用修飾的靜態方法,就好像是自己的方法一樣:
1 2 3 4 5 6
|
package com.chenxyt.java.test; public class Printer { public static void print(String msg){ System.out.println(msg); } }
|
然后另一個包中使用import static導入這個類
1 2 3 4 5 6 7
|
package com.chenxyt.java.practice; import static com.chenxyt.java.test.Printer.*; public class TestStatic{ public static void main(String[] args) { print("This is TestStatic"); } }
|
運行結果:

五、總結
static是Java語言中的一個很重要的關鍵字,主要用途有三個方面修飾成員變量,修飾成員方法以及修飾代碼塊。使用static修飾的成員變量在類加載的時候就已經被初始化了,它屬於類變量,不屬於某個對象,所有該類的實例化對象擁有同一個靜態成員變量副本,常用的用途可以用它來做計數器。