Java static關鍵字/靜態變數/靜態方法/final關鍵字
原文:www.weixueyuan.net/view/6003.html
http://www.weixueyuan.net/view/6004.html
靜態變數和靜態方法能夠通過類名來訪問,不需要建立一個類的物件來訪問該類的靜態成員,所以static修飾的成員又稱作類變數和類方法。靜態變數與例項變數不同,例項變數總是通過物件來訪問,因為它們的值在物件和物件之間有所不同。
static 的記憶體分配
靜態變數屬於類,不屬於任何獨立的物件,所以無需建立類的例項就可以訪問靜態變數。之所以會產生這樣的結果,是因為編譯器只為整個類建立了一個靜態變數的副本,也就是隻分配一個記憶體空間,雖然有多個例項,但這些例項共享該記憶體。例項變數則不同,每建立一個物件,都會分配一次記憶體空間,不同變數的記憶體相互獨立,互不影響,改變 a 物件的例項變數不會影響 b 物件。
public class Demo { static int i; int j; public static void main(String[] args) { Demo obj1 = new Demo(); obj1.i = 10; obj1.j = 20; Demo obj2 = new Demo(); System.out.println("obj1.i=" + obj1.i + ", obj1.j=" + obj1.j); System.out.println("obj2.i=" + obj2.i + ", obj2.j=" + obj2.j); } }
執行結果:
obj1.i=10, obj1.j=20
obj2.i=10, obj2.j=0
上面的程式碼中,i 是靜態變數,通過 obj1 改變 i 的值,會影響到 obj2;j 是例項變數,通過 obj1 改變 j 的值,不會影響到 obj2。這是因為 obj1.i 和 obj2.i 指向同一個記憶體空間,而 obj1.j 和 obj2.j 指向不同的記憶體空間。
注意:類變數(class variables)用關鍵字 static 修飾,在類載入的時候,分配類變數的記憶體,以後再生成類的例項物件時,將共享這塊記憶體(類變數),任何一個物件對類變數的修改,都會影響其它物件。
關於靜態變數和靜態方法的總結
- 一個類的靜態方法只能訪問靜態變數;
- 一個類的靜態方法不能夠直接呼叫非靜態方法;
- 如訪問控制權限允許,靜態變數和靜態方法也可以通過物件來訪問,但是不被推薦;
- 靜態方法中不存在當前物件,因而不能使用 this,當然也不能使用 super;
- 靜態方法不能被非靜態方法覆蓋;
- 構造方法不允許宣告為 static 的;
- 區域性變數不能使用static修飾。
靜態初始器(靜態塊)
塊是由大括號包圍的一段程式碼。靜態初始器(Static Initializer)是一個存在於類中、方法外面的靜態塊。靜態初始器僅僅在類裝載的時候(第一次使用類的時候)執行一次,往往用來初始化靜態變數。
public class Demo {
public static int i;
static{
i = 10;
System.out.println("Now in static block.");
}
public void test() {
System.out.println("test method: i=" + i);
}
public static void main(String[] args) {
System.out.println("Demo.i=" + Demo.i);
new Demo().test();
}
}
執行結果:Now in static block.
Demo.i=10
test method: i=10
靜態匯入
用來匯入類的靜態變數和靜態方法。靜態匯入的好處是可以簡化一些操作,例如輸出語句 System.out.println(); 中的 out 就是 System 類的靜態變數,可以通過 import static java.lang.System.*; 將其匯入,下次直接呼叫 out.println() 就可以了。
import static java.lang.System.*;
import static java.lang.Math.random;
public class Demo {
public static void main(String[] args) {
out.println("產生的一個隨機數:" + random());
}
}
執行結果:產生的一個隨機數:0.05800891549018705
final關鍵字
具體規定如下:
- final 修飾的類不能被繼承。
- final 修飾的方法不能被子類重寫。
- final 修飾的變數(成員變數或區域性變數)即成為常量,只能賦值一次。
- final 修飾的成員變數必須在宣告的同時賦值,如果在宣告的時候沒有賦值,那麼只有 一次賦值的機會,而且只能在構造方法中顯式賦值,然後才能使用。
- final 修飾的區域性變數可以只宣告不賦值,然後再進行一次性的賦值。
注意:
如果將引用型別(任何類的型別)的變數標記為 final,那麼該變數不能指向任何其它物件。但可以改變物件的內容,因為只有引用本身是 final 的。
如果變數被標記為 final,其結果是使它成為常數。想改變 final 變數的值會導致一個編譯錯誤。
final 也可以用來修飾類(放在 class 關鍵字前面),阻止該類再派生出子類。
方法也可以被 final 修飾,被 final 修飾的方法不能被覆蓋;變數也可以被 final 修飾,被 final 修飾的變數在建立物件以後就不允許改變它們的值了。一旦將一個類宣告為 final,那麼該類包含的方法也將被隱式地宣告為 final,但是變數不是。
被 final 修飾的方法為靜態繫結,不會產生多型(動態繫結),程式在執行時不需要再檢索方法表,能夠提高程式碼的執行效率。在Java中,被 static 或 private 修飾的方法會被隱式的宣告為 final,因為動態繫結沒有意義。
JVM 中的即時編譯器能夠實時監控程式的執行資訊,可以準確的知道類之間的繼承關係。如果一個方法沒有被覆蓋並且很短,編譯器就能夠對它進行優化處理,這個過程為稱為內聯(inlining)。例如,內聯呼叫 e.getName() 將被替換為訪問 e.name 變數。