1. 程式人生 > 實用技巧 >static關鍵字詳解

static關鍵字詳解

主要四種場景:

  1. 修飾成員變數和成員方法
  2. 靜態程式碼塊
  3. 修飾類(只能修飾內部類)
  4. 靜態導包(用來匯入類中的靜態資源,1.5之後的新特性)

修飾成員變數和成員方法(常用)

被 static 修飾的成員屬於類,不屬於單個這個類的某個物件,被類中所有物件共享,可以並且建議通過類名呼叫。被static 宣告的成員變數屬於靜態成員變數,靜態變數 存放在 Java 記憶體區域的方法區。

方法區與 Java 堆一樣,是各個執行緒共享的記憶體區域,它用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。雖然Java虛擬機器規範把方法區描述為堆的一個邏輯部分,但是它卻有一個別名叫做 Non-Heap(非堆),目的應該是與 Java 堆區分開來。

HotSpot 虛擬機器中方法區也常被稱為 “永久代”,本質上兩者並不等價。僅僅是因為 HotSpot 虛擬機器設計團隊用永久代來實現方法區而已,這樣 HotSpot 虛擬機器的垃圾收集器就可以像管理 Java 堆一樣管理這部分記憶體了。但是這並不是一個好主意,因為這樣更容易遇到記憶體溢位問題。

呼叫格式:

  • 類名.靜態變數名
  • 類名.靜態方法名()

如果變數或者方法被 private 則代表該屬性或者該方法只能在類的內部被訪問而不能在類的外部被方法。

靜態程式碼塊

靜態程式碼塊定義在類中方法外, 靜態程式碼塊在非靜態程式碼塊之前執行(靜態程式碼塊—非靜態程式碼塊—構造方法)。 該類不管建立多少物件,靜態程式碼塊只執行一次.

一個類中的靜態程式碼塊可以有多個,位置可以隨便放,它不在任何的方法體內,JVM載入類時會執行這些靜態的程式碼塊,如果靜態程式碼塊有多個,JVM將按照它們在類中出現的先後順序依次執行它們,每個程式碼塊只會被執行一次。

靜態程式碼塊對於定義在它之後的靜態變數,可以賦值,但是不能訪問.

當 Singleton 類載入時,靜態內部類 SingletonHolder 沒有被載入進記憶體。只有當呼叫getUniqueInstance()方法從而觸發SingletonHolder.INSTANCE時 SingletonHolder 才會被載入,此時初始化 INSTANCE 例項,並且 JVM 能確保 INSTANCE 只被例項化一次。

這種方式不僅具有延遲初始化的好處,而且由 JVM 提供了對執行緒安全的支援。

靜態導包

格式為:import static

這兩個關鍵字連用可以指定匯入某個類中的指定靜態資源,並且不需要使用類名呼叫類中靜態成員,可以直接使用類中靜態成員變數和成員方法

補充內容

靜態方法與非靜態方法

靜態方法屬於類本身,非靜態方法屬於從該類生成的每個物件。 如果您的方法執行的操作不依賴於其類的各個變數和方法,請將其設定為靜態(這將使程式的佔用空間更小)。 否則,它應該是非靜態的。

你可以像這樣呼叫靜態方法:Foo.method1()。 如果您嘗試使用這種方法呼叫 method2 將失敗。 但這樣可行:Foo bar = new Foo(1);bar.method2();

總結:

  • 在外部呼叫靜態方法時,可以使用”類名.方法名”的方式,也可以使用”物件名.方法名”的方式。而例項方法只有後面這種方式。也就是說,呼叫靜態方法可以無需建立物件。
  • 靜態方法在訪問本類的成員時,只允許訪問靜態成員(即靜態成員變數和靜態方法),而不允許訪問例項成員變數和例項方法;例項方法則無此限制

static{}靜態程式碼塊與{}非靜態程式碼塊(構造程式碼塊)

相同點: 都是在JVM載入類時且在構造方法執行之前執行,在類中都可以定義多個,定義多個時按定義的順序執行,一般在程式碼塊中對一些static變數進行賦值。

不同點: 靜態程式碼塊在非靜態程式碼塊之前執行(靜態程式碼塊—非靜態程式碼塊—構造方法)。靜態程式碼塊只在第一次new執行一次,之後不再執行,而非靜態程式碼塊在每new一次就執行一次。 非靜態程式碼塊可在普通方法中定義(不過作用不大);而靜態程式碼塊不行。

一般情況下,如果有些程式碼比如一些專案最常用的變數或物件必須在專案啟動的時候就執行的時候,需要使用靜態程式碼塊,這種程式碼是主動執行的。如果我們想要設計不需要建立物件就可以呼叫類中的方法,例如:Arrays類,Character類,String類等,就需要使用靜態方法, 兩者的區別是 靜態程式碼塊是自動執行的而靜態方法是被呼叫的時候才執行的.

非靜態程式碼塊與建構函式的區別是: 非靜態程式碼塊是給所有物件進行統一初始化,而建構函式是給對應的物件初始化,因為建構函式是可以多個的,執行哪個建構函式就會建立什麼樣的物件,但無論建立哪個物件,都會先執行相同的構造程式碼塊。也就是說,構造程式碼塊中定義的是不同物件共性的初始化內容。

參考