1. 程式人生 > >Java中final關鍵字的使用

Java中final關鍵字的使用

《Java程式設計思想》

final是Java的一個非訪問控制修飾符(non-access modifier),可以用於修飾變數、方法和類,有著“不可變”的作用。下面我們簡單看一下final有哪些用法。

1 final變數

當一個變數被final修飾時,它分為兩種情況:
當這個變數是一個基本資料型別時,這時就意味著該變數是可讀的、不可更改的常量(constant),對於常量,有兩個方面的應用:
(1)編譯時常數,它永遠不會改變,對於編譯期的常數,編譯器可將常數值“封裝”到需要的計算過程裡。也就是說,計算可在編譯期間提前執行,從而節省執行時的一些開銷;
(2)在執行期初始化的一個值,我們不希望它發生變化;
而當這個變數是一個物件的引用時,它表示的則是引用只能被賦值一次(引用不可變,但物件本身可變)。

		final int MY_CONSTANT_INT = 1;//編譯時常數
//		MY_CONSTANT_INT = 2; //編譯錯誤
		
		final int MY_RUNTIME_CONSTANT_INT = (int) (Math.random() * 10);//執行時常數
//		MY_RUNTIME_CONSTANT_INT = 3;//編譯錯誤
		
		final List<String> MY_CONSTANT_LIST = new ArrayList<>();
//		MY_CONSTANT_LIST = new ArrayList<>();//編譯錯誤
		MY_CONSTANT_LIST.add("aa");

2 final方法

當一個方法被宣告為final時,意味著該方法不能被子類覆蓋重寫(overridden)。

class BaseClazz{
	
	public final void method() {
		
	}
}

class ChildClazz extends BaseClazz{
	//編輯錯誤
//	public final void method() {
//		
//	}
}

同時,在執行上,final方法比final方法有著更高的效率,編譯器會把對final方法的呼叫轉換為內聯(inline)方法呼叫,即忽略為執行方法呼叫機制(將自變數壓入堆疊;跳至方法程式碼並執行它;跳回來;清除堆疊自變數;最後對返回值進行處理)而採取的常規程式碼嵌入方法。相反,它會用方法主體內實際程式碼的一個副本來替換方法呼叫。這樣做可避免方法呼叫時的系統開銷。當然,若方法體積太大,那麼程式也會變得雍腫,可能感受不到嵌入程式碼所帶來的任何效能提升。因為任何提升都被花在方法內部的時間抵消了。 Java 編譯器能自動偵測這些情況,並頗為“明智”地決定是否嵌入一個 final 方法。
另外,類的 private 方法都自動成為 final方法。

3 final類

如果一個類被final修飾的話,則表明這個類是不可繼承的,我們常用的String就是一個final修飾的類:

final class BaseClazz{
	
	public final void method() {
		
	}
}

//錯誤
//class ChildClazz extends BaseClazz{
//	
//}

另外,final類的方法都自動成為 final方法。

4 空白final

空白final是指,已經宣告但並未進行初始化的final變數,但編譯器會保證該變數在實際使用前得到正確的初始化。

	final int BLANK_FINAL_INT;//空白final
	BLANK_FINAL_INT = 2;

但如果空白final作為成員變量出現,那麼如何保證它的初始化呢,兩種方式:

public class BlankFinalTest {
	final int BLANK_FINAL_MEM_INT1;
	//程式碼塊初始化
	{
		BLANK_FINAL_MEM_INT1 = 1;
	}
	
	final int BLANK_FINAL_MEM_INT2;
	//建構函式初始化
	public BlankFinalTest(int i) {
		BLANK_FINAL_MEM_INT2 = i;
	}
}

使用空白final建立一個不可變(內容不可變)的物件:

class ImmutableClazz{
	
	public final int CONSTAIN_II;

	public ImmutableClazz(int i) {
		CONSTAIN_II = i;
	}
	
}
//...
	public static void main(String[] args) {
		ImmutableClazz immutableClazz = new ImmutableClazz(11);
//		immutableClazz.CONSTAIN_II = 2;//編譯錯誤
	}

5 final和static的區別

final和static修飾符常成對出現,用於宣告常量,但final和static有著什麼區別呢?
static成員變量表示只儲存一份副本,並且所有物件共享該變數;而final的作用是用來保證變數不可變。

final class BaseClazz{
	
    public final double FINAL_DD = Math.random();
    public static double STATIC_DD = Math.random();
	
	public final void method() {
		
	}
	
	public static void main(String[] args) {
		BaseClazz b1 = new BaseClazz();
		BaseClazz b2 = new BaseClazz();
		System.out.println(b1.FINAL_DD);
		System.out.println(b2.FINAL_DD);
		System.out.println(b1.STATIC_DD);
		System.out.println(b2.STATIC_DD);
	}
}

輸出:

0.17103733059790327
0.237554219342485
0.7814031755793921
0.7814031755793921