1. 程式人生 > >static 關鍵字詳解

static 關鍵字詳解

static 關鍵字

static 關鍵字主要有以下四種使用場景

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

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

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

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

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

呼叫格式:

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

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

測試方法:

public class StaticBean {

    String name;
    靜態變數
    static int
age; public StaticBean(String name) { this.name = name; } 靜態方法 static void SayHello() { System.out.println(Hello i am java); } @Override public String toString() { return StaticBean{ + name=' + name + ''' + age + age + '}'
; } }
public class StaticDemo {

    public static void main(String[] args) {
        StaticBean staticBean = new StaticBean(1);
        StaticBean staticBean2 = new StaticBean(2);
        StaticBean staticBean3 = new StaticBean(3);
        StaticBean staticBean4 = new StaticBean(4);
        StaticBean.age = 33;
        StaticBean{name='1'age33} StaticBean{name='2'age33} StaticBean{name='3'age33} StaticBean{name='4'age33}
        System.out.println(staticBean+ +staticBean2+ +staticBean3+ +staticBean4);
        StaticBean.SayHello();Hello i am java
    }

}

靜態程式碼塊

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

靜態程式碼塊的格式是

static {    
語句體;   
}

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

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

靜態內部類

靜態內部類與非靜態內部類之間存在一個最大的區別,我們知道非靜態內部類在編譯完成之後會隱含地儲存著一個引用,該引用是指向建立它的外圍內,但是靜態內部類卻沒有。沒有這個引用就意味著:

  1. 它的建立是不需要依賴外圍類的建立。
  2. 它不能使用任何外圍類的非static成員變數和方法。

Example(靜態內部類實現單例模式)

public class Singleton {
    
    宣告為 private 避免呼叫預設構造方法建立物件
    private Singleton() {
    }
    
    宣告為 private 表明靜態內部該類只能在該 Singleton 類中被訪問
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getUniqueInstance() {
        return SingletonHolder.INSTANCE;
    }
}

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

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

靜態導包

格式為:import static

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



  Math. --- 將Math中的所有靜態資源匯入,這時候可以直接使用裡面的靜態方法,而不用通過類名進行呼叫
  如果只想匯入單一某個靜態方法,只需要將換成對應的方法名即可
 
import static java.lang.Math.;

  換成import static java.lang.Math.max;具有一樣的效果
 
public class Demo {
	public static void main(String[] args) {
 
		int max = max(1,2);
		System.out.println(max);
	}
}

補充內容

靜態方法與非靜態方法

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

Example

class Foo {
    int i;
    public Foo(int i) { 
       this.i = i;
    }

    public static String method1() {
       return An example string that doesn't depend on i (an instance variable);
       
    }

    public int method2() {
       return this.i + 1;  Depends on i
    }

}

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

總結:

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

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

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

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

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

Example

public class Test {
    public Test() {
        System.out.print(預設構造方法!--);
    }

     非靜態程式碼塊
    {
        System.out.print(非靜態程式碼塊!--);
    }
     靜態程式碼塊
    static {
        System.out.print(靜態程式碼塊!--);
    }

    public static void test() {
        System.out.print(靜態方法中的內容! --);
        {
            System.out.print(靜態方法中的程式碼塊!--);
        }

    }
    public static void main(String[] args) {

        Test test = new Test();   
        Test.test();靜態程式碼塊!--靜態方法中的內容! --靜態方法中的程式碼塊!--
    }

當執行 Test.test(); 時輸出:

靜態程式碼塊!--靜態方法中的內容! --靜態方法中的程式碼塊!--

當執行 Test test = new Test(); 時輸出:

靜態程式碼塊!--非靜態程式碼塊!--預設構造方法!--

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

參考

  • httpsblog.csdn.netchen13579867831articledetails78995480
  • httpwww.cnblogs.comchenssyp3388487.html
  • httpwww.cnblogs.comQian123p5713440.html

你若盛開,清風自來。 歡迎關注我的微信公眾號:“Java面試通關手冊”,一個有溫度的微信公眾號。公眾號後臺回覆關鍵字“1”,你可能看到想要的東西哦!