final作爲java的關鍵字,它可以修飾類,方法,變量及參數,但是有很多朋友可能不太清楚它怎麼用,什麼時候用,有什麼優點,下面我們來一一解釋。
類
當final修飾一個類時,表明其爲最終類,它不能被繼承,並且類中所有的屬性和方法都默認是final類型,如String,Integer等包裝類均爲final類。
方法
被final修飾的方法不可被重寫。它可以防止任何繼承類修改方法的意義和實現,而且,使用final修飾方法的執行效率一般高於普通方法,這裏不得不提一下Java的內聯機制。
當我們調用方法時,實際上是將程序的執行轉移到該方法所在的內存地址上,將該方法執行完後,再返回到執行該方法前的位置,這種轉移操作要求在轉移前保存當前的數據以及內存地址,在執行完後再恢復現場,繼續按照轉移前的地址執行,也就是通常所說的壓棧和出棧(這段文字有點繞口,簡單來說,比如A方法在執行到第10行的時候調用了B方法,JVM會先保存A方法當前數據和執行地址,然後跳轉到B方法所在的內存地址執行B方法,執行完後,再返回A方法第十行繼續執行),因此,函數調用有一定時間和空間方面的開銷,對於函數體積不大,但是頻繁調用的函數來說,這個開銷就會放大。
因此,對於這種函數體積不大又頻繁調用的的方法,我們可以通過內聯函數來提升運行效率,當我們對一個方法使用final修飾時,這個方法就有可能成爲內聯函數(JVM會根據方法的執行效率決定是否內聯)。
看下面代碼,解釋函數內聯前後的區別。
內聯前:
class A {
int value;
public final int get(){
return value;
}
}
public class B {
public void sum() {
A a = new A();
//調用a的get方法
int x = a.get();
}
}
內聯後:
class A {
int value;
public final int get(){
return value;
}
}
public class B {
public void sum() {
A a = new A();
//此處將get方法展開爲內聯函數
int x = a.value;
}
}
變量
使用final修飾的變量稱爲常量(大寫字母表示),只能被賦值一次,且賦值之後無法改變,這裏的變量又可以分爲基本類型變量和引用類型變量,final修飾基本類型變量時,變量的值不可改變;修飾引用變量時,變量指向的對象地址不可改變。
這裏還涉及到了一個類似C語言的宏替換概念,由於final修飾的String變量不可更改,所以,當一個String變量被final修飾時,這個值在編譯期就可以確定,所有將該變量直接替換爲它對應的值,如下:
public class test {
public static void main(String[] args) {
final String a = "hello";
String b = "hello";
final String c = "world";
String d = "hello" + "world";
String e = a + c;
String f = b + c;
String g = "helloworld";
System.out.println(g == d);//true
System.out.println(g == e);//true
System.out.println(g == f);//false
}
}
在編譯期,由於a和c的值已經確定並且不會再更改(效果同d),所以e的值能夠在編譯期就確定下來,直接指向了常量區的g,前兩個均爲true;再看下f,由於b值的不確定性,所以在編譯期不能確定其值,只能在運行時確認,所以(g == f)爲false。
參數
final修飾的參數有一個只讀的屬性,即可以讀取該參數,但是無法更改參數的值,同修飾變量一樣,當參數爲基本類型時,該參數的值不可改變;當參數爲引用類型時,參數的引用地址不可改變。
final的內存語義
在《【併發編程】揭開volatile的神祕面紗》中,說到了volatile可以禁止指令重排序,final同樣有這樣的作用,對於final域,編譯器和處理器要遵守兩個重排序規則。
在構造函數內對一個final域的寫入,與隨後把這個被構造對象的引用賦值給一個引用變量,這兩個操作之間不能重排序。
意思是說,在對象引用爲任意線程可見之前,對象的final域已經被正確初始化了(JVM禁止把final域的寫重排序到構造函數之外,要保證該效果,還要確保final引用沒有從構造函數溢出)。
初次讀一個包含final域的對象的引用,與隨後初次讀這個final域,這兩個操作之間不能重排序。
意思是說,在讀一個對象的final域之前,一定會先讀包含這個final域的對象的引用。