final 是Java 中重要關鍵字之一,能夠應用於類、方法以及變量上。這篇文章中將講解什麼是 final 關鍵字?將變量、方法和類聲明爲 final 表明了什麼?使用 final 的好處是什麼?java
final 在 Java 中是一個保留的關鍵字,能夠聲明成員變量、方法、類以及本地變量。一旦你將引用聲明做 final,你將不能改變這個引用了,編譯器會檢查代碼,若是試圖將變量再次初始化的話,編譯器會報編譯錯誤。編程
凡是對成員變量或者本地變量(在方法中的或者代碼塊中的變量稱爲本地變量)聲明爲 final 的都叫做 final 變量。final 變量常常和 static 關鍵字一塊兒使用,做爲常量。下面是 final 變量的例子:緩存
public static final String NAME = "wupx"; NAME = new String("wupx"); //invalid compilation error
final 變量是隻讀的。安全
final 也能夠聲明方法,Java 裏用 final 修飾符去修飾一個方法的惟一正確用途就是表達:這個方法本來是一個虛方法,如今經過 final 來聲明這個方法不容許在派生類中進一步被覆寫(override)。多線程
Java 中非私有的成員方法默認都是虛方法,而虛方法就能夠在派生類中被覆寫。爲了保證某個類上的某個虛方法不在派生類中被進一步覆寫,就須要使用 final 修飾符來聲明,讓編譯器(例如 javac)與 JVM 共同檢查並保證這個限制老是成立。ide
下面引用 R 大 在知乎上的回答來打破「用 final 修飾方法可讓對這個方法的調用變快」的流言:函數
曾經有一種廣爲流傳的說法是用final修飾方法可讓對這個方法的調用變快。這種說法在現代主流的優化JVM上都是不成立的(例如Oracle JDK / OpenJDK HotSpot VM、IBM J9 VM、Azul Systems Zing VM等)。這是由於:能用final修飾的虛方法,其派生類中必然不可能存在對其覆寫的版本,因而能夠斷定這個虛方法只有一個可能的調用目標;而若是此時把這個final修飾符去掉,這些先進的JVM均可以經過「類層次分析」(Class Hierarchy Analysis,CHA)來發現這個方法在派生類中沒有進一步覆寫的版本,因而一樣能夠斷定這個虛方法只有一個可能的調用目標。而後二者的優化程度會如出一轍,不管是從「不須要經過虛分派而能夠直接調用目標」(稱爲「去虛化」,devirtualization)仍是從「便於內聯」的角度看,這兩種狀況都是同樣的。性能
而若是某個類層次結構中本來某個虛方法就存在多個覆寫版本的話,那麼原本也不可能對這個虛方法加上final修飾,因此就算這種狀況下去虛化變得困難,鍋也不能讓「由於沒用final修飾」來背。優化
使用final關鍵字在現代主流的優化JVM上不會提高性能。this
下面是 final 方法的例子:
class User{ public final String getName(){ return "user:wupx"; } } class Reader extends User{ @Override public final String getName(){ return "reader wupx"; //compilation error: overridden method is final } }
使用 final 來修飾的類叫做 final 類,final類一般功能是完整的,它們不能被繼承,Java 中有許多類是 final 的,好比 String, Interger 以及其餘包裝類。下面是 final 類的實例:
final class User{ } class Reader extends User{ //compilation error: cannot inherit from final class }
對於 final 變量,編譯器和處理器都要遵照兩個重排序規則:
實際上這兩個規則也正是針對 final 變量的寫與讀。寫的重排序規則能夠保證,在對象引用對任意線程可見以前,對象的 final 變量已經正確初始化了,而普通變量則不具備這個保障;讀的重排序規則能夠保證,在讀一個對象的 final 變量以前,必定會先讀這個對象的引用。若是讀取到的引用不爲空,根據上面的寫規則,說明對象的 final 變量必定以及初始化完畢,從而能夠讀到正確的變量值。
若是 final 變量的類型是引用型,那麼構造函數內,對一個 final 引用的對象的成員域的寫入,與隨後在構造函數外把這個被構造對象的引用賦值給一個引用變量,這兩個操做之間不能重排序。
實際上這也是爲了保證 final 變量在對其餘線程可見以前,可以正確的初始化完成。
下面爲使用 final 關鍵字的一些好處:
參考
《Java編程思想》