1、涵義
最一般的意思就是聲明 “這個東西不能改變”。之是以要禁止改變,可能是考慮到兩方面的因素:設計或效率。 final 關鍵字可以用來修飾變量、方法和類,修飾變量表示變量不能被修改,修飾方法表示方法不能被重寫,修飾類表示類不能被繼承。
由于以下兩個原因,資料的恒定不變是很有用的。
- 它可以是一個永不改變的"編譯期常量"(僅限基本資料類型,提高編譯效率)。
- 它可以是一個在運作期間被初始化的值,而你不希望他改變。
2、修飾變量
當對對象引用而不是對原始類型運用final時,其含義會有一點令人迷惑。對于原始類型,final使數值恒定不變,而對于對象引用,final使引用恒定不變。一旦引用被初始化指向一個對象,就無法對他改變以指向另一個對象。然而,對象其本身卻是可以修改的,Java并未提供使任何對象恒定不變的途徑。來個Demo 如下:
public class Value
{
int i=1;
}
public class FinalData
{
final int i1 = 9;
static final int I2 = 99;
public static final int I3 = 39;
final int i4 = (int)(Math.random()*20);//特别注意
static final int i5 = (int)(Math.random()*20);//特别注意
Value v1 = new Value();
final Value v2 = new Value();
static final Value v3 = new Value();
final int[] a = { 1, 2, 3, 4, 5, 6 };
public void print(String id)
{
System.out.println(id + ": " + "i4 = " + i4 + ", i5 = " + i5);
}
public static void main(String[] args)
{
FinalData fd1 = new FinalData();
//! fd1.i1++; // Error:final的值不能被改變
fd1.v2.i++; // 對象的成員未被設成final,不會報錯
fd1.v1 = new Value(); // OK --不是final對象
for(int i = 0; i < fd1.a.length; i++)
fd1.a[i]++; // 對象的成員未被設成final,不會報錯
// fd1.v2 = new Value(); // Error: Can't
// fd1.v3 = new Value(); // 不能将一個final引用指向另一個
// fd1.a = new int[3];
fd1.print("fd1");
System.out.println("Creating new FinalData");
FinalData fd2 = new FinalData();
fd1.print("fd1");
fd2.print("fd2");
}
}

不能由于某樣東西的屬性是 final,就認定它的值能在編譯時期知道。 i4 和 i5 向大家證明了這一點。它們在運作期間使用随機生成的數字。例子的這一部分也向大家揭示出将final 值設為 static 和非 static 之間的差異 。記住一點:static局部變量在所處子產品在初次運作時進行初始化工作,且隻操作一次。
請注意,帶有恒定初始值(即編譯期常量)的final static 原始類型全部用大寫字母命名,并且字與字之間用下劃線來隔開。一個既是static又是final的域隻占一份不能改變的存儲空間。
3、空白Final
Java強行要求我們對 final 進行指派處理—— 要麼在定義字段時使用一個表達 式,要麼在每個建構器中。這樣就可以確定 final 字段在使用前獲得正确的初始化。 空白final在關鍵字final的使用上提供了更大的額靈活性。為此一個類中的final成員就可以實作依對象而有所不同,卻又保持其恒定不變的特性。
4、修飾方法
之是以要使用 final 方法,可能是出于對兩方面理由的考慮:
1、為方法“上鎖”,防止任何繼承類改變它的本來含義。設計程式時,若希望一個方法的行為在繼承期間保持不變,而且不可被覆寫或改寫,就可以采取這種做法。
2、将一個方法設成 final 後,編譯器就可以把對那個方法的所有調用都置入“嵌入”調用裡。隻要編譯器發現一個 final 方法調用,就會(根據它自己的判斷)忽略為執行方法調用機制而采取的正常代碼插入方法(将自變量壓入堆棧;跳至方法代碼并執行它;跳回來;清除堆棧自變量;最後對傳回值進行處理)。相反,它會用方法主體内實際代碼的一個副本來替換方法調用。這樣做可避免方法調用時的系統開銷。當然,若方法體積太大,那麼程式也會變得雍腫,可能受到到不到嵌入代碼所帶來的任何性能提升。因為任何提升都被花在方法内部的時間抵消了。 Java 編譯器能自動偵測這些情況,并頗為“明智”地決定是否嵌入一個 final 方法。然而,最好還是不要完全相信編譯器能正确地作出所有判斷。通常,隻有在方法的代碼量非常少,或者想明确禁止方法被覆寫的時候,才應考慮将一個方法設為final。
類内所有 private 方法都自動成為 final。由于我們不能通路一個 private 方法,是以它絕對不會被其他方法覆寫。
Java允許你以在參數清單中以聲明的方式将參數指明為final。這意味着你無法在方法中更改參數引用所指向的對象。
大多數情況下,設定final方法并不會對我們程式的整體性能産生什麼改觀。是以,最好根據設計來決定是否使用final,而不是出于試圖提高性能。
5、修飾類
如果說整個類都是 final(在它的定義前冠以 final 關鍵字),就表明自己不希望從這個類繼承,或者不允許其他任何人采取這種操作。換言之,出于這樣或那樣的原因,我們的類肯定不需要進行任何改變;或者出于安全方面的理由,我們不希望進行子類化(子類處理)。
請注意,根據你的選擇,final類的資料成員可以是final,也可以不是。不論類是否被定義為final,相同的規則都适用于final的資料成員。當然,Final 類的所有方法都預設是final修飾的。