1. 程式人生 > >簡單易懂的理解Java中的static、final以及static final

簡單易懂的理解Java中的static、final以及static final

 

首先,從最基本的概念上來說:

1.static,static通常修飾方法、成員變數等,強調它所修飾的屬性只有一個

首先關於static修飾的方法,稱之為靜態方法。靜態方法可以直接通過類名被呼叫,任何類生成的例項也可以呼叫,因而被static修飾過的方法不能有this或者super這種需要有例項的關鍵字,也不能直接訪問所屬類的例項變數或例項方法。

關於static修飾的變數,靜態變數,表示靜態變數在記憶體中只有一個拷貝,JVM只為靜態變數分配一次記憶體,在載入類的過程中便完成靜態變數的記憶體分配,同靜態方法一樣,靜態變數可以用類名直接訪問,同時也是推薦的方法,而不要用物件來訪問(因為靜態變數不屬於單一物件)。

要注意static修飾的方法或者變數初始化在編譯期。

 

2.final,final通常修飾類、方法、成員變數等。

final修飾類時表示類不能被繼承,沒有子類,類中方法預設是final的。

final修飾方法的時候表示方法不能被子類的方法覆蓋,但可以被繼承。

final比較關鍵的就是當它修飾變數時表示常量,即只能被賦值一次,並且賦值後不再改變。

 

3.static final(同final static一樣,一般寫作前者),static final在修飾基本資料型別的變數時,表示該變數為常數或者說常量(建立後不能被修改,值為固定的),與final修飾基本資料型別時是相同的,只是兩者在變數的初始化順序

上有所不同。

 

final和static final其實是不容易理解的兩個關鍵詞,樓主發現一個比較好的程式碼例子,感謝@奮鬥的蝸牛cn的提供,接下來我們藉助程式碼來理解(以下程式碼內容並不複雜,希望大家可以耐心閱讀

首先定義一個計數的類,其中計數器被static修飾。(帶入之前的介紹,counter這個變數應當是唯一的。)

package difStaticFinalAndFinal;

class Counter {
    private static int counter;
    private int id = counter++;
    
    public String toString(){
        return "Counter: " + id;
    }
}

然後是一個測試類,在測試類中我們用static final修飾了一個Counter的例項,用final也修飾了一個Counter例項。

package difStaticFinalAndFinal;

class Test {  
    static final Counter staticFinalCounter= new Counter();  
    final Counter finalCounter = new Counter();
    
    public String toString(){
        return "finalCounter=" + finalCounter + ",\n" + "staticFinalCounter=" + staticFinalCounter;
    }
}

最後在main函式中我們建兩個測試類的例項並列印。

package difStaticFinalAndFinal;

public class StaticFinal {
    public static void main(String[] args) {
        System.out.println("First Object:");
        System.out.println(new Test());
        System.out.println("Second Object:");
        System.out.println(new Test());
    }
}

可以看到輸出結果如下圖:

分析一下輸出結果,看到staticFinalCounter中id首先被賦值為0,並且保持沒變。原因就是在被static修飾的情況下,staticFinalCounter只被初始化一次,所以第二次便不會經歷一個Counter構造的過程,保持了id為0.

而finalCounter值增加了1,可能會有朋友考慮final修飾的不是常量嗎,為什麼值會改變?是因為這裡final修飾的並不是基本型別,而是一個例項化的類(引用),引用的內容是可以改變的,而不可以改變引用指向的物件。

有興趣的同學可以自己測試一下逐步除錯,可以發現static修飾的變數或者物件,只會在程式編譯期的時候初始化一次,再之後都會被跳過,(即被JVM分配的記憶體就在那裡,不會再新分配)。