Java中final修飾符對不同變數的不同影響
final修飾符可以用來修飾類、方法和變數,用於表示它修飾的類、方法和變數不可改變。final修飾變數時,表示該變數一旦獲得了初始值就不可被改變。
由於final變數獲取初始值之後就不能重新賦值,所以final修飾成員變數和區域性變數時有一定程度的不同。
final成員變數
成員變數是隨類初始化或者物件初始化而初始化的。在初始化時,系統會為類變數或者例項變數分配記憶體並分配預設值。
對於final修飾的成員變數而言,一旦有了初始值,就不能再被重新賦值。因此,如果沒有在定義成員變數時指定初始值,也沒有在初始化塊、構造器中為成員變數指定初值,那麼這些成員變數將一直是系統預設分配的0、’\u0000’、false或者null。這是沒有意義的,所以Java語法規定:final修飾的成員變數必須由程式設計師顯示地指定初始值。
final區域性變數
系統不會為區域性變數進行初始化,區域性變數必須由程式設計師顯示初始化。因此,使用final修飾區域性變數時,既可以在定義時指定預設值,也可以不指定預設值。
注意這段程式碼是有語法錯誤的:
public class Main {
public void test(final int a){
a = 5;//語法錯誤
}
public static void main(String[] args){
final int a = 4;
Main main = new Main();
main.test(a);
}
}
因為形參在傳入方式時,會根據系統傳入的引數來完成初始化,因此使用final修飾的形參不能被賦值。
final 修飾的基本型別變數和引用型別變數的區別
當使用final修飾基本型別變數時,不能對基本型別變數重新賦值,因此基本型別變數不能被改變。但是對於引用型別變數而言,他儲存的僅僅是一個引用,final只保證這個引用型別變數所引用的地址不會改變,即一直引用一個物件,但這個物件可以被改變。
考慮下面這個示例:
public class Main {
public static void main(String[] args){
final int[] a ;
final int b;
int[] c = {1,2,3,4};
int d = 10;
a = c;
b = d;
c[2] = 10;
System.out.println(a[2]);
//output 10
d = 1;
System.out.println(b);
//output 10
}
}
可以執行“巨集替換”的final變數
對於一個final變數來說,只要滿足三個條件,這個final變數就不再是一個變數,而是相當於一個直接量。
- 使用final修飾符修飾
- 在定義該final變數時指定了初始值
- 該初始值可以在編譯時就被確認下來。
考慮下面的程式碼演示:
public class Main {
public static void main(String[] args){
final String a="Amos ",b="H";
final String c = a+b;
final String d = "Amos H";
String e="Amos ",f="H";
final String g=e+f;
System.out.println(c==d);
//output true
System.out.println(c==g);
//output false
}
}
因為變數c和變數d的值在編譯的時候就已經確定了,所以它們同時指向常量池中的Amos H 。因此輸出true。而對於變數g來說,它在定義的時候系統無法確認它的值,所以自然不能指向常量池。因此自然輸出false。
如果希望g也指向常量值,只要將e,f也定義為final變數即可。