標籤:
在 Java 中,聲明類、變數和方法時,可使用關鍵字 final 來修飾。final 所修飾的資料具有“終態”的特徵,表示“最終的”意思。具體規定如下:
- final 修飾的類不能被繼承。
- final 修飾的方法不能被子類重寫。
- final 修飾的變數(成員變數或局部變數)即成為常量,只能賦值一次。
- final 修飾的成員變數必須在聲明的同時賦值,如果在聲明的時候沒有賦值,那麼只有 一次賦值的機會,而且只能在構造方法中顯式賦值,然後才能使用。
- final 修飾的局部變數可以只聲明不賦值,然後再進行一次性的賦值。
final 一般用於修飾那些通用性的功能、實現方式或取值不能隨意被改變的資料,以避免被誤用,例如實現數學三角方法、冪運算等功能的方法,以及數學常量π=3.141593、e=2.71828 等。
事實上,為確保終態性,提供了上述方法和常量的 java.lang.Math 類也已被定義為final 的。
需要注意的是,如果將參考型別(任何類的類型)的變數標記為 final,那麼該變數不能指向任何其它對象。但可以改變對象的內容,因為只有引用本身是 final 的。
如果變數被標記為 final,其結果是使它成為常數。想改變 final 變數的值會導致一個編譯錯誤。下面是一個正確定義 final 變數的例子:
- public final int MAX_ARRAY_SIZE = 25; // 常量名一般大寫
常量因為有 final 修飾,所以不能被繼承。
請看下面的代碼:
- public final class Demo{
- public static final int TOTAL_NUMBER = 5;
- public int id;
- public Demo() {
- // 非法,對final變數TOTAL_NUMBER進行二次賦值了
- // 因為++TOTAL_NUMBER相當於 TOTAL_NUMBER=TOTAL_NUMBER+1
- id = ++TOTAL_NUMBER;
- }
- public static void main(String[] args) {
- final Demo t = new Demo();
- final int i = 10;
- final int j;
- j = 20;
- j = 30; // 非法,對final變數進行二次賦值
- }
- }
final 也可以用來修飾類(放在 class 關鍵字前面),阻止該類再派生出子類,例如 Java.lang.String 就是一個 final 類。這樣做是出於安全原因,因為要保證一旦有字串的引用,就必須是類 String 的字串,而不是某個其它類的字串(String 類可能被惡意繼承並篡改)。
方法也可以被 final 修飾,被 final 修飾的方法不能被覆蓋;變數也可以被 final 修飾,被 final 修飾的變數在建立對象以後就不允許改變它們的值了。一旦將一個類聲明為 final,那麼該類包含的方法也將被隱式地聲明為 final,但是變數不是。
被 final 修飾的方法為靜態繫結,不會產生多態(動態綁定),程式在運行時不需要再檢索方法表,能夠提高代碼的執行效率。在Java中,被 static 或 private 修飾的方法會被隱式的聲明為 final,因為動態綁定沒有意義。
由於動態綁定會消耗資源並且很多時候沒有必要,所以有一些程式員認為:除非有足夠的理由使用多態性,否則應該將所有的方法都用 final 修飾。
這樣的認識未免有些偏激,因為 JVM 中的即時編譯器能夠即時監控程式的運行資訊,可以準確的知道類之間的繼承關係。如果一個方法沒有被覆蓋並且很短,編譯器就能夠對它進行最佳化處理,這個過程為稱為內聯(inlining)。例如,內聯調用 e.getName() 將被替換為訪問 e.name 變數。這是一項很有意義的改進,這是由於CPU在處理調用方法的指令時,使用的分支轉移會擾亂預取指令的策略,所以,這被視為不受歡迎的。然而,如果 getName() 在另外一個類中被覆蓋,那麼編譯器就無法知道覆蓋的代碼將會做什麼操作,因此也就不能對它進行內聯處理了。
10.Java final關鍵字:阻止繼承和多態