簡單易懂的理解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分配的記憶體就在那裡,不會再新分配)。