1. 程式人生 > 實用技巧 >final關鍵字

final關鍵字

Java中的final關鍵字可以用來修飾類、方法和變數(包括例項變數和區域性變數)

Tip:

例項變數是類中方法外定義的變數,例項變數可以使用訪問修飾符public和private修飾,使用public修飾說明該變數對子類可見,使用private修飾則子類不可見,該變數只能在本類可見,例項變數具有預設值;

區域性變數是在方法中定義的變數,不能用訪問修飾符修飾,但是可以使用final關鍵字修飾(區域性變數本省就是一種有限制的變數,只可以區域性呼叫,因此沒有必要使用訪問修飾符修飾)

final關鍵字的基本用法
final修飾類
使用final修飾類則該類不能被繼承,同時類中的所有成員方法都會被隱式定義為final方法(只有在需要確保類中的所有方法都不被重寫時才使用final修飾類)。

final修飾類的成員變數是可以更改的

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);
}

}
final修飾方法
使用final修飾方法可以將方法“鎖定”,以防止任何繼承類對方法的修改,也即使用final修飾方法,則子類無法重寫(但並不影響繼承和過載,即子類呼叫父類方法不受影響)。

final修飾變數
使用final關鍵字修飾變數是使用最多的情況

使用final修飾變數的值不能做再次更改,即不能重新賦值
如果final修飾的變數是基本資料型別,則變數的值不可更改;
如果final修飾的變數是引用資料型別,則該變數不能再次指向其他引用(如重新指向新的物件或陣列)但是該變數本身的內容可以再做修改(如陣列本身的內容,或者物件的屬性的修改)

無論final修飾例項變數還是區域性變數,都必須在使用前顯式賦初值
Java中的例項變數系統會對其預設賦初值,但是區域性變數必須先聲明後賦值再使用:

在下面的例子中,沒有對src賦初值,如果程式正確,那麼會在2步驟中給src賦值,但是如果2步驟中讀檔案出現問題,那麼在4步驟中使用src就會出錯,因此從程式的健壯性考慮,應對src賦初值,即0步驟

public void fun(){

//BufferedImage src = null;//0. 宣告的同時賦值
BufferedImage src;//1. 這裡不用賦初值,也不會出錯
try{
	src = ImageIO.read(new File("1.jpg"));//2.
} catch (Exception e){
//3. 如果出異常了就會進入這裡,那麼src可能無法被賦值
}

System.out.println(src.getHeight()); //4. src不一定有值,所以無法使用

}

雖然對於例項變數,系統會預設賦初值,但是Java仍然規定final修飾的例項變數必須顯式賦初值。例項變數顯式賦值的時機可以是在宣告時直接賦值,也可以先宣告,後在構造方法中賦值(對於含有多個構造方法,必須在每個構造方法中都顯示賦值)

如果靜態變數同時被final修飾則可以將變數視為全域性變數,即在整個類載入期間,其值不變。(static保證變數屬於整個類,在類載入時只對其分配一次記憶體;final保證變數的值不被改變)
final 關鍵字相關問題
final變數和普通變數的區別
final變數一旦被初始化賦值之後,就不能再被賦值了。

public class Test{
public static void main(String[] args){
String a = "hello2";
final String b = "hello";
String d = "hello";
String c = b + 2;
String e = d + 2;
System.out.println((a == c));//輸出true
System.out.println((a == e));//輸出false
}
}
當final變數是基本資料型別以及String型別時,如果在編譯期間能知道它的確切值,則編譯器會把它當做編譯期常量使用。也就是說在用到該final變數的地方,相當於直接訪問的這個常量,不需要在執行時確定。(類似於c語言中的巨集替換)

上面的一段程式碼中,由於變數b被final修飾,因此會被當做編譯器常量,所以在使用到b的地方會直接將變數b 替換為它的 值。而對於變數d的訪問卻需要在執行時通過連結來進行。

final和static
使用final修飾是用以保證變數不被改變,而使用static修飾成員變數,則成員變數在類中只儲存一份副本。

在下列程式碼中,i的兩次輸出都不一樣,而j的兩次輸出為同一值。

public class Test {
public static void main(String[] args){
MyClass myClass1 = new MyClass();
MyClass myClass2 = new MyClass();
System.out.println(myClass1.i);
System.out.println(myClass1.j);
System.out.println(myClass2.i);
System.out.println(myClass2.j);

}

}

class MyClass{
public final double i = Math.random();
public static double j = Math.random();
}