final中文意思:最終的,不可改變的。那么使用final作為修飾符修飾類、方法、變量、局部變量、參數就具有了一些別的意義。
成員變量是隨著類初始化或者對象初始化而初始化,當類初始化時,系統會為該類變量分配內存并分配默認值;當創建對象時,系統會為該對象的實例變量分配內存,并分配默認值,也就是說,當執行靜態初始化代碼塊時可以對類變量賦初始值,也可以在初始化代碼塊、構造器中指定初始值。
對于final修飾的成員變量而言,一旦有了初始值,就不能被重新賦值。
class FinalTest{ static final int i = 1; public static void main(String[] args){ i =2;//報錯,不可以給final修飾變量重復賦值 }}
如果既沒有在定義成員變量時指定初始值,也沒有在初始化塊、構造器中為成員變量指定初始值,那么這些成員變量的值將一直是系統的默認分配的值0、"/u0000"、false、或者null等。
class FinalTest{ static int i ; public static void main(String[] args){ System.out.PRintln(i);//輸出:0,整數默認0 }}
這些成員變量如果被final修飾,那么也就完全失去了存在的意義。因此java語法規定:final修飾的成員變量必須有程序員顯示的指定初始值。
class FinalTest{ static final int i ; //這樣是錯誤滴,違反語法規定! public static void main(String[] args){ }}歸納起來,final修飾的類變量、實例變量能指定初始值的地方如下。
1、 類變量:必須在靜態初始化塊中指定初始值或聲明該類變量時指定的初始值,而且只能在兩個地方的其中之一指定。
//在靜態代碼塊中初始化值class FinalTest{ static final int i ; static{ i = 2; } public static void main(String[] args){ System.out.println(i); }}在聲明final修飾的變量時指定初始值
class FinalTest{ static final int i = 3; public static void main(String[] args){ System.out.println(i); }}錯誤的案例:靜態代碼塊中賦值+聲明變量時賦值 = 錯誤
class FinalTest{ static final int i = 3; static{ //不能再次賦值,final int i聲明時已指定初始值 i = 2; }}
2、 實例變量:必須在非靜態初始化塊、聲明該實例變量或構造器中指定初始值,而且只能在三個地方的其中之一指定。
在構造方法中指定初始值
class Person{ public Person(){ name ="小明"; } final String name;}
在構造代碼塊中指定初始值:
class Person{ { name ="小明"; } final String name;}聲明時直接賦值:class Person{ final String name = "小明";}final修飾的實例變量,要么在定義該實例變量時指定初始值,要么在普通初始化塊或構造器中為該實例變量指定初始值。但需要注意的是,如果普通初始化塊已經為某個實例變量指定了初始值,則不能再在構造器中為該實例變量指定初始值;final修飾的類變量,要么在定義該類變量時指定初始化值,要么在靜態初始化塊中位該類變量指定初始值。
實例變量不能在靜態初始化塊中指定初始值,因為靜態初始化塊是靜態成員,不可訪問實例變量-非靜態成員;類變量不能在普通初始化塊中指定初始值,因為類變量在類初始化階段已經被初始化了,普通初始化塊不能對其重新賦值。
//沒有給初始化值,就不要訪問.
class Person{ { System.out.println(name); name ="小明"; } final String name;}
final局部變量
系統不會對局部變量進行初始化,局部變量必須由程序員顯示初始化(直接賦值)。
錯誤的:
class FinalTest{ public static void main(String[] args){ final String str; //局部變量是沒有初始值的,未賦值使用會報錯 System.out.println(str); }}正確的:
class FinalTest{ public static void main(String[] args){ final String str =”abcd”; System.out.println(str); }}定義時不賦值,使用時,賦值:
class FinalTest{ public static void main(String[] args){ final String str; str ="abcd"; System.out.println(str); }}
因此使用final修飾局部變量時,即可在定義時指定默認值,也可以不指定默認值,什么時候使用再賦值,但是只能賦值1次,不能重復賦值。

final修飾基本類型變量和引用類型變量的區別
當使用final修飾基本類型變量時,不能對基本類型變量重新賦值,因此基本類型變量不能被改變,但對于引用類型變量而言,它保存的僅僅是一個引用,final只保證這個引用類型變量所引用的地址不會改變,即一直引用同一個對象,但這個對象完全可以發生改變。
class FinalTest{ public static void main(String[] args){ /* person變量記錄地址值 不可以改變常量指向的對象。 */ final Person person = new Person(); //person= new Person(); 不可以重新賦值 //但是不影響他所指向的對象本身數據的更改 System.out.println(person.name); person.name= "小明"; System.out.println(person.name); }}class Person{ String name;}也就是說,使用final修飾的引用類型變量不能被重新復制,但可以改變引用類型所引用對象的內容。
宏替換:
可執行“宏替換“的final變量(字面量常量)
對一個final變量來說,不管他是類變量、實例變量,還是局部變量,只要該變量滿足3個條件,這個final變量就不再是一個變量,而是相當于一個直接量,即字面量常量
1、使用final修飾符修飾
2、在定義final變量時指定了初始值
3、該初始值可以編譯時就確定下來
//TODOclass FinalTest{ static final String school = "北工商" ; public static void main(String[] args){ //在編譯時,遇到school直接替換成北工商 System.out.println(school); System.out.println("北工商"); }}通過上面程序,我們可以看出來, 變量school滿足3個條件,這個時候我們就說,運行時變量school其實根本不存在,當執行system.out.println(school)代碼時,實際轉換為執行System.out.println("北工商");
當編譯時,遇到了這種情況,java編譯器就會將程序中所有用到該變量名的地方直接替換成所對應的值。
除了上面那種為final變量賦值時直接賦值的情況外,如果被賦值的表達式只是基本算數表達式或者字符串拼裝運算,沒有訪問普通變量,調用方法,那么這些也是滿足上面3個條件,java編譯器同樣會將這種final變量當成“宏變量”處理。
//TODO做字符串拼接class FinalTest{ static final String xuexiao = "北工商" ; static final String xueyuan = "軟工學院" ; static final String banji = "1607A" ; static final String info = xuexiao +xueyuan +banji; public static void main(String[] args){ //在編譯時,遇到info直接替換成北工商軟工學院1607A System.out.println(info); }}final方法
final修飾的方法不可以被重寫,如果處于某些原因,不希望子類重寫父類的某個方法,則可以使用final修飾該方法。
java提供Object類里就有一個final方法:getClass(),因為java不希望任何類重寫這個方法,所以使用final吧這個方法密封起來。但對于該類提供的toString()和equals()方法,都允許子類重寫,因此沒有使用final修飾他們
//翻原碼,做案例

final類
final修飾類不可以有子類,不可以被繼承。
當子類繼承父類,將可以訪問到父類內部數據,并可以通過重寫父類方法改變實現細節,這可能導致一些不安全的因素。為了保證某個類不可以被繼承,則可以使用final修飾這個類,下面代碼示范了final修飾的類不可以被繼承。
不可變類
不可變類意思就是創建該類的對象后,該對象的實例變量不可以改變。java提供了8個包裝類和string類都是不可變類。當創建他們的實例后,其實例的實例變量不可以改變。
例如通過構造器構造Double、String、Integer對象,傳入的值在他們類中肯定有變量來記錄傳入的值,但是Double、String、Integer類并沒有提供修改該值的方法。

如果需要創建自定義不可變類,需遵守如下規則:
1、使用private和final修飾符來修飾該類的成員。
2、提供帶參構造器,對該變量進行初始化。
3、僅提供getValue方法,不提供setVaule方法,因為該指是常量就無法改變。
4、如果有必要,重寫equals和hashCode方法,通過該不可變量來判斷該實例對象是否相等。
class BufferName{ public boolean equals(Object obj){ if(obj== null ){ return false; } if(!(obj instanceof BufferName)){ return false; } BufferName bn = (BufferName)obj; if(this.name.equals(bn.name)){ return true; } return false; } //不可變類實例變量 final private String name; String age; String address;}
新聞熱點
疑難解答