java final修飾符


一、Java中final修飾符既可以修飾類、方法,也可以修飾變量,基本規則如下:

1)用final修飾的類不能被擴展,也就是說不可能有子類;
2)用final修飾的方法不能被替換或隱藏:
  ①使用final修飾的實例方法在其所屬類的子類中不能被替換(overridden);
  ②使用final修飾的靜態方法在其所屬類的子類中不能被重定義(redefined)而隱藏(hidden);
3)用final修飾的變量最多只能賦值一次,在賦值方式上不同類型的變量或稍有不同:
  ①靜態變量必須明確賦值一次(不能只使用類型缺省值);作為類成員的靜態變量,賦值可以在其聲明
   中通過初始化表達式完成,也可以在靜態初始化塊中進行;作為接口成員的靜態變量,賦值只能在其
   聲明中通過初始化表達式完成;
  ②實例變量同樣必須明確賦值一次(不能只使用類型缺省值);賦值可以在其聲明中通過初始化表達式
   完成,也可以在實例初始化塊或構造器中進行;
  ③方法參數變量在方法被調用時創建,同時被初始化為對應實參值,終止於方法體(body)結束,在此
   期間其值不能改變;
  ④構造器參數變量在構造器被調用(通過實例創建表達式或顯示的構造器調用)時創建,同時被初始化
   為對應實參值,終止於構造器體結束,在此期間其值不能改變;
  ⑤異常處理器參數變量在有異常被try語句的catch子句捕捉到時創建,同時被初始化為實際的異常對象
   ,終止於catch語句塊結束,在此期間其值不能改變;
  ⑥局部變量在其值被訪問之前必須被明確賦值;

 

示例一:
interface IncludeFinalInterface{
    //接口中定義的變量都是public static final的
    int staticVar = 2009; //作為接口成員的變量,其賦值只能在聲明中完成
}
class IncludeFinal{
    static final int staticVar;
    final int instanceVar;
   
    IncludeFinal(){
        instanceVar = 9; //實例變量的賦值還可以在構造器中進行
    }
    IncludeFinal(final boolean sameAsStatic){
        instanceVar = sameAsStatic ? staticVar : 9;
//      sameAsStatic = false;//不能編譯,final修飾的構造器參數變量在構造器體中不能被再次賦值
    }
   
    static final void showStaticVar(){
        System.out.println("IncludeFinal.staticVar = " + staticVar);
    }
    final void showInstanceVar(){
        System.out.println("IncludeFinal.instatnceVar = " + instanceVar);
    }
    void show(final boolean showStatic){
        if( showStatic )
            showStaticVar();
        else
            showInstanceVar();
//      showStatic = false; //不能編譯,final修飾的方法參數變量在方法體中不能被再次賦值
    }
    static void demoExceptionHandlerParameter(){
        try{
            System.out.println(10/0);
        }
        catch(final ArithmeticException ae){
            ae.printStackTrace();
//          ae = null;//不能編譯,final修飾的異常處理器參數變量在catch語句塊中不能被再次賦值
        }
    }
    static void showLocalVar(){
        final int localVar;
        localVar = 209; //局部變量在其值被訪問之前必須被明確賦值,
                        //當然在其聲明中同時指定一個初始化值似乎是一個更好的選擇
        System.out.println("LocalVar = " + localVar);
    }
    static{ //除在聲明中同時初始化外,作為類成員的靜態變量,其賦值還可以在靜態初始化塊中進行
        staticVar = 2009;
    }
//  { //實例變量的賦值還可以在實例初始化塊中進行
//      instanceVar = 9;
//  }
}
public class FinalTest extends IncludeFinal {
//  static void showStaticVar(){ //編譯錯誤,不能重定義父類中用final修飾的靜態方法
//      System.out.println("FinalTest.staticVar = " + staticVar);
//  }
//  void showInstanceVar(){ //編譯錯誤,不能替換父類中用final修飾的實例方法
//      System.out.println("FinalTest.instatnceVar = " + instanceVar);
//  }  
    public static void main(String[] args){
        showStaticVar();
        demoExceptionHandlerParameter();
        showLocalVar();
        new IncludeFinal(false).show(false);
    }
}
運行結果:
IncludeFinal.staticVar = 2009
java.lang.ArithmeticException: / by zero
    at IncludeFinal.demoExceptionHandlerParameter(FinalTest.java:32)
    at FinalTest.main(FinalTest.java:61)
LocalVar = 209
IncludeFinal.instatnceVar = 9

二、關於final變量的進一步說明:

1)定義:blank final變量是其聲明中不包含初始化表達式的final變量。
2)對於引用類型變量,final修飾符表示一旦賦值該變量就始終指向堆中同一個對象,不可改變,但是其
  所指對象本身(其狀態)是可以改變的;不象C++中的const,在Java中沒有辦法僅通過一個final就可
  聲明一個對象的不變性(immutability)。
3)常變量(constant variable):
  ①定義:常變量是用編譯時常量表達式初始化的帶有final修飾符的基本類型或字符串類型變量;
  ②無論靜態變量還是實例變量,如果它是常變量,則其引用在編譯時會被解析成該常變量所表示的值,
   在class文件中並不存在任何對常變量域的引用;也正是基於此,當在源代碼中修改某個常變量域的
   初始值並重新編譯后,該改動並不為其他class文件可見,除非對他們也重新編譯。
示例二:
public class ConstantVariable {
    static final int staticVar = 10 + 8; //靜態變量staticVar是一個常變量
    final int instanceVar =  100 + 8; //實例變量instanceVar也是一個常變量
    //靜態變量notConstantVariable不是常變量,因為其初始化表達式不是編譯時常量表達式
    static final int notConstantVariable = (int)(Math.random() * 10);
}
public class Test {
    public static void main(String[] args){
        //對類ConstantVariable中常變量staticVar的引用
        System.out.println("staticVar = " + ConstantVariable.staticVar);
        //對類ConstantVariable中常變量instanceVar的引用
        System.out.println("instanceVar = " + new ConstantVariable().instanceVar);
        //對類ConstantVariable中靜態變量notConstantVariable的引用
        System.out.println("notConstantVariable = " + ConstantVariable.notConstantVariable);
    }
}
運行結果:
staticVar = 18
instanceVar = 108
notConstantVariable = 2
Test.class文件的反編譯結果:
import java.io.PrintStream;
public class Test
{   //從該文件很容易驗證,當在ConstantVariable.java中修改常變量的值並重新編譯后,類Test的運行結果不會受任何影
  //響
,除非把Test.java文件也重新編譯一遍
    public Test(){}
    public static void main(String args[]){
        //對常變量ConstantVariable.staticVar的引用在編譯后直接被其值“18”替換

    System.out.println("staticVar = 18"); 
        (new ConstantVariable()).getClass();
        //對類ConstantVariable中常變量instanceVar的引用在編譯后直接被其值“108”替換
        System.out.println((new StringBuilder("instanceVar = ")).append(108).toString());
        //ConstantVariable.notConstantVariable不是常變量,所以其引用得以保持
        System.out.println(
            (new StringBuilder("notConstantVariable = ")).
            append(ConstantVariable.notConstantVariable).

            toString()

        );
    }
}
4)用final修飾的參數變量,雖然並不為所有人喜歡,但它的確為編譯器提供了附加的信息,一方面可以
  增強其錯誤檢測能力,另一方面也有助於其對代碼的優化。
5)final修飾符與其他修飾符共同出現時,書寫順序可參考下面一行:
  Annotation public protected private abstract static final synchronized native transient volatile strictfp


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM