英語里final這個單詞大家都知道是“最終的”意思,其實還有一個意思是“不可更改的”。在Java里,final關鍵字作“不可更改的”來解釋更合適,即由final修飾的東西是“不可更改的”。final可以修飾變數、成員方法和類,還可以修飾方法的參數,但參數歸根結底還是變數。下麵是詳細解釋。 作者: 蟬 ...
英語里final這個單詞大家都知道是“最終的”意思,其實還有一個意思是“不可更改的”。在Java里,final關鍵字作“不可更改的”來解釋更合適,即由final修飾的東西是“不可更改的”。final可以修飾變數、成員方法和類,還可以修飾方法的參數,但參數歸根結底還是變數。下麵是詳細解釋。
作者: 蟬蟬
請尊重作者勞動成果,轉載請在標題註明“轉載”字樣,並標明原文鏈接:
http://www.cnblogs.com/chanchan/p/7936388.html
1.final可以修飾成員變數、局部變數
(1).final修飾的變數的值不能更改,即不能再次賦值,即使賦的新值與舊值一樣也不可以。
如:
final int i = 1; //定義int型變數i,並賦初值為1
//i = 2; //wrong
//i = 1; //wrong
註釋掉的這兩行都不可以,都會出現“The final local variable i can not be assigned.It must be blank and not using a compound assignment.”的錯誤。
(2).final修飾的成員變數和局部變數需要在使用前賦值。
1).對成員變數而言,可以在定義時直接賦初值;
2).也可以先定義不賦初值,再在構造方法中對其賦值。
就是說,對象創建好後,該對象的final成員變數要保證是賦了初值的,早點(定義時賦值)、晚點(在構造方法里賦值)都沒關係。
註:第二種情況,如果有多個構造方法就比較麻煩了,每個構造方法都要有賦值語句,否則會出現“The blank final field height may not have been initialized.”的錯誤。
3).如果靜態成員變數被修飾為final,那麼該變數可看成是全局變數,即在類的整個載入期間,其值都不可變。
如:
static final String citizenship = "Chinese";
citizenship既是static又是final的,static說明它是屬於整個類的,類載入時就分配記憶體了(參見筆記9),final說明其值不可變,即,位置固定內容也固定。
(3).把成員變數和局部變數從變數的類型上來分,
1).當變數為基本數據類型時,變數的值不可更改,如上面的變數i;
2).當變數為引用類型時,變數本身的值不可更改,即該變數不能指向其他的對象或數組;
但該變數指向的對象或數組本身的內容是可以改變的;
如:
final Person per = new Person(); //定義了一個Person類的對象引用per,並指向了new的對象
//per = new Person(); //重新創建一個Person類對象,並讓per指向它,會出現與上面一樣的錯誤,即final修飾的引用類型變數不能重新賦值
per.name = "me"; //per指向的對象本身的內容可以更改
為方便理解起見,請參考下麵的記憶體圖:
2.final可以修飾成員方法
(1).final修飾的成員方法不能被子類重寫,即,當父類的方法為final時,子類不能與父類有方法名、參數類型、參數個數及參數順序都一樣的方法;父類方法為private時除外,詳見下麵的(3);但子類可以調用父類的final方法。
見下麵的代碼:
Person類的方法: final void finalMethod() { int i = 2; System.out.println("finalMethod: i = " + i); } 在TestMain中由Student類的對象引用調用: public class TestMain { public static void main(String[] args) { Student stu = new Student(); stu.finalMethod(); }
輸出結果為:finalMethod: i = 2
(2).訪問許可權為private的方法預設為final的,但子類不可以調用private的方法,關於訪問許可權修飾符的問題,詳見筆記10。
(3).當父類某方法為private final,子類的成員方法與父類的該成員方法重名但僅由final修飾時,這時算不算重寫呢?
Person類的方法: private final void priFinalMethod() { System.out.println("Person:priFinalMethod"); } Student類的方法: final void priFinalMethod() { System.out.println("Student:priFinalMethod"); } TestMain類: package human; public class TestMain { public static void main(String[] args) { Person per = new Person(); Student stu = new Student(); Person per1 = stu; // per.priFinalMethod(); stu.priFinalMethod(); // per1.priFinalMethod(); } Person類的main方法: public static void main(String[] args) { Person per = new Person(); Student stu = new Student(); Person per1 = stu; per.priFinalMethod(); stu.priFinalMethod(); per1.priFinalMethod(); }
TestMain類的輸出是:
Student:priFinalMethod
1).其中,TestMain類中註釋掉的兩行都提示該方法不可見;
2).對於per來說,private的方法僅本類可見,在TestMain類中是不可見的,所以per是不能調用priFinalMethod方法的;
3).對於per1來說,per1是指向Student對象的引用,per1只能調用Student中重寫過的方法及Person類中的方法,由於這裡仍然提示該方法不可見,結合2)可知,priFinalMethod方法是沒被子類重寫的,否則就可以調用了;
Person類的輸出是:
Person:priFinalMethod
Student:priFinalMethod
Person:priFinalMethod
前兩行好理解,最後一行,per1調用的是Person類中的priFinalMethod,進一步說明該方法未被子類重寫;
否則,會優先調用子類的priFinalMethod方法的。
3.final可以修飾成員方法的參數
由final修飾的成員方法的參數也是不能更改的,其實參數就是變數,具體參見1即可。
這裡還涉及到形參與實參的概念,具體大家自己瞭解吧。
4.final可以修飾類
由final修飾的類不能被子類繼承,其成員方法也預設為final的,但成員變數是可以改變的,見下麵代碼:
package human; public final class FinalClass { int i = 1; void test() { System.out.println("FinalClass:test"); } public static void main( String[] args ) { FinalClass ficl = new FinalClass(); System.out.println("ficl.i = " + ficl.i); ficl.i = 2; System.out.println("ficl.i = " + ficl.i); } }
輸出結果為:
ficl.i = 1
ficl.i = 2
可見可以修改i的值。
附測試源碼:
Person類:
package human; public class Person { //class Person{ String name; int age; String gender; //筆記18:final修飾成員變數,及成員變數為類引用時的情況 final int height = 160; // final int height; final EduBackground edu = new EduBackground(); public Person() { // final height = 160; } //筆記18:final修飾局部變數、修飾成員方法、修飾方法的參數 //修飾局部變數時,局部變數的值不能改變 void finalLocal() { // final int i = 1; final int i; // i = 3; final EduBackground edu = new EduBackground(); // edu = new EduBackground(); i = 1; System.out.println("finalLocal: i = " + i); } //修飾方法的參數時,參數不能被修改 void finalArgs(final int i) { // i = 3; System.out.println("finalArgs: i = " + i); } void finalArgs(final EduBackground edu) { // edu = new EduBackground(); System.out.println("finalArgs: edu"); } //修飾成員方法時,成員方法不能被子類重寫 final void finalMethod() { int i = 2; System.out.println("finalMethod: i = " + i); } private final void priFinalMethod() { System.out.println("Person:priFinalMethod"); } public static void main(String[] args) { Person per = new Person(); Student stu = new Student(); Person per1 = stu; per.priFinalMethod(); stu.priFinalMethod(); per1.priFinalMethod(); } }
Student類:
package human; public class Student extends Person { String stuNumber; int score; public Student() { } //筆記18:子類不能重寫父類被final修飾的方法 // final void finalMethod() { // int i = 2; // System.out.println("finalMethod: i = " + i); // } final void priFinalMethod() { System.out.println("Student:priFinalMethod"); } }
EduBackground類:
package human; //public class EduBackground extends FinalClass { public class EduBackground { String primarySchool; String secondarySchool; String juniorHSchool; String seniorHSchool; String university; public EduBackground() { } }