對於Java中的 final 關鍵字,我們首先可以從字面意思上去理解,百度翻譯顯示如下:

也就是說 final 英文意思表示是最后的,不可更改的。那么對應在 Java 中也是表達這樣的意思,可以用 final 關鍵字修飾變量、方法和類。不管是用來修飾什么,其本意都是指 “它是無法更改的”,這是我們需要牢記的,為什么要無法更改?無非就是設計所需或者能提高效率,與前面介紹 static 關鍵字需要記住其與對象無關的理念一樣,牢記 final 的不可變的設計理念后再來了解 final 關鍵字的用法,便會順其自然了。
1、修飾變量
稍微有點Java基礎的都知道用final關鍵字修飾的變量稱為常量,常量的意思是不可更改。變量為基本數據類型,不可更改很容易理解,那么對於引用類型呢?不可能改的是其引用地址,還是對象的內容?
我們首先構造一個實體類:Person
1 package com.ys.bean; 2 3 /** 4 * Create by YSOcean 5 */ 6 public class Person { 7 private String name; 8 9 public Person(String name) { 10 this.name = name; 11 } 12 13 public String getName() { 14 return name; 15 } 16 17 public void setName(String name) { 18 this.name = name; 19 } 20 }
接着根據創建一個 Person 對象:

可以看到,首先通過 final 關鍵字修飾一個對象 p,然后接着將 p 對象指向另一個新的對象,發現報錯,也就是說final修飾的引用類型是不能改變其引用地址的。
接着我們改動 p 對象的 name 屬性:

發現程序沒有報錯。
結論:被 final 修飾的變量不可更改其引用地址,但是可以更改其內部屬性。
2、修飾方法
final 關鍵字修飾的方法不可被覆蓋。
在《Java編程思想》第 4 版 7.8.2 章節 final 方法p176 頁這樣描述:使用 final 方法原因有兩個:
①、第一個原因是把方法鎖定,以防止任何繼承類修改它的含義,這是出於設計的考慮:想要確保在繼承中使方法的行為保持不變,並且不會被覆蓋。
②、第二個原因是效率,在 Java 的早期實現中,如果將一個方法聲明為 final,就是同意編譯器將針對該方法的所有調用都轉為內嵌調用,內嵌調用能夠提高方法調用效率,但是如果方法很大,內嵌調用不會提高性能。而在目前的Java版本中(JDK1.5以后),虛擬機可以自動進行優化了,而不需要使用 final 方法。
所以final 關鍵字只有明確禁止覆蓋方法時,才使用其修飾方法。
PS:《Java編程思想》中指出類中所有的 private 方法都隱式指定為 final 的,所以對於 private 方法,我們顯式的聲明 final 並沒有什么效果。但是我們創建一個父類,並在父類中聲明一個 private 方法,其子類中是能夠重寫其父類的private 方法的,這是為什么呢?
父類:Parent.class
package com.ys.bean; /** * Create by YSOcean */ public class Parent { private void say(){ System.out.println("parent"); } }
子類:Son.class
package com.ys.bean; /** * Create by YSOcean */ public class Son extends Parent { private void say(){ System.out.println("son"); } }
其實仔細看看,這種寫法是方法的覆蓋嗎?我們通過多態的形式並不能調用到父類的 say() 方法:

並且,如果我們在子類的 say() 方法中,添加 @Override 注解也是會報錯的。

所以這種形式並不算方法的覆蓋。
3、修飾類
final 修飾類表示該類不可被繼承。
也就是說不希望某個類有子類的時候,用final 關鍵字來修飾。並且由於是用 final 修飾的類,其類中所有的方法也被隱式的指為 final 方法。
在 JDK 中有個最明顯的類 String ,就是用 final 修飾的,將 String 類用 final 修飾很重要的一個原因是常量池。關於 String 類的描述,可以參考我的這篇博客。

