溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java中final關(guān)鍵字的原理和應(yīng)用

發(fā)布時間:2021-06-24 12:09:42 來源:億速云 閱讀:272 作者:chen 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“Java中final關(guān)鍵字的原理和應(yīng)用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“Java中final關(guān)鍵字的原理和應(yīng)用”吧!

final 是Java 中重要關(guān)鍵字之一,可以應(yīng)用于類、方法以及變量上。這篇文章中將講解什么是 final 關(guān)鍵字?將變量、方法和類聲明為 final 代表了什么?使用 final 的好處是什么?

final 關(guān)鍵字是什么?

final 在 Java 中是一個保留的關(guān)鍵字,可以聲明成員變量、方法、類以及本地變量。一旦你將引用聲明作 final,你將不能改變這個引用了,編譯器會檢查代碼,如果試圖將變量再次初始化的話,編譯器會報編譯錯誤。

final 變量

凡是對成員變量或者本地變量(在方法中的或者代碼塊中的變量稱為本地變量)聲明為 final 的都叫作 final 變量。final 變量經(jīng)常和 static 關(guān)鍵字一起使用,作為常量。下面是 final 變量的例子:

public static final String NAME = "wupx";
NAME = new String("wupx"); //invalid compilation error

final 變量是只讀的。

final 方法

final 也可以聲明方法,Java 里用 final 修飾符去修飾一個方法的唯一正確用途就是表達:這個方法原本是一個虛方法,現(xiàn)在通過 final 來聲明這個方法不允許在派生類中進一步被覆寫(override)。

Java 中非私有的成員方法默認都是虛方法,而虛方法就可以在派生類中被覆寫。為了保證某個類上的某個虛方法不在派生類中被進一步覆寫,就需要使用 final 修飾符來聲明,讓編譯器(例如 javac)與 JVM 共同檢查并保證這個限制總是成立。

下面引用 R 大 在知乎上的回答來打破“用 final 修飾方法可以讓對這個方法的調(diào)用變快”的流言:

曾經(jīng)有一種廣為流傳的說法是用final修飾方法可以讓對這個方法的調(diào)用變快。這種說法在現(xiàn)代主流的優(yōu)化JVM上都是不成立的(例如Oracle JDK / OpenJDK HotSpot VM、IBM J9 VM、Azul Systems Zing VM等)。這是因為:能用final修飾的虛方法,其派生類中必然不可能存在對其覆寫的版本,于是可以判定這個虛方法只有一個可能的調(diào)用目標;而如果此時把這個final修飾符去掉,這些先進的JVM都可以通過“類層次分析”(Class Hierarchy Analysis,CHA)來發(fā)現(xiàn)這個方法在派生類中沒有進一步覆寫的版本,于是同樣可以判定這個虛方法只有一個可能的調(diào)用目標。然后兩者的優(yōu)化程度會一模一樣,無論是從“不需要通過虛分派而可以直接調(diào)用目標”(稱為“去虛化”,devirtualization)還是從“便于內(nèi)聯(lián)”的角度看,這兩種情況都是一樣的。

而如果某個類層次結(jié)構(gòu)中原本某個虛方法就存在多個覆寫版本的話,那么本來也不可能對這個虛方法加上final修飾,所以就算這種情況下去虛化變得困難,鍋也不能讓“因為沒用final修飾”來背。

使用final關(guān)鍵字在現(xiàn)代主流的優(yōu)化JVM上不會提升性能。

下面是 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 類,final類通常功能是完整的,它們不能被繼承,Java 中有許多類是 final 的,比如 String, Interger 以及其他包裝類。下面是 final 類的實例:

final class User{

}

class Reader extends User{  //compilation error: cannot inherit from final class

}

內(nèi)存模型中的 final

對于 final 變量,編譯器和處理器都要遵守兩個重排序規(guī)則:

  • 構(gòu)造函數(shù)內(nèi),對一個 final 變量的寫入,與隨后把這個被構(gòu)造對象的引用賦值給一個變量,這兩個操作之間不可重排序

  • 首次讀一個包含 final 變量的對象,與隨后首次讀這個 final 變量,這兩個操作之間不可以重排序

實際上這兩個規(guī)則也正是針對 final 變量的寫與讀。寫的重排序規(guī)則可以保證,在對象引用對任意線程可見之前,對象的 final 變量已經(jīng)正確初始化了,而普通變量則不具有這個保障;讀的重排序規(guī)則可以保證,在讀一個對象的 final 變量之前,一定會先讀這個對象的引用。如果讀取到的引用不為空,根據(jù)上面的寫規(guī)則,說明對象的 final 變量一定以及初始化完畢,從而可以讀到正確的變量值。

如果 final 變量的類型是引用型,那么構(gòu)造函數(shù)內(nèi),對一個 final 引用的對象的成員域的寫入,與隨后在構(gòu)造函數(shù)外把這個被構(gòu)造對象的引用賦值給一個引用變量,這兩個操作之間不能重排序。

實際上這也是為了保證 final 變量在對其他線程可見之前,能夠正確的初始化完成。

final 關(guān)鍵字的好處

下面為使用 final 關(guān)鍵字的一些好處:

  • final 關(guān)鍵字提高了性能,JVM 和 Java 應(yīng)用都會緩存 final 變量

  • final 變量可以安全的在多線程環(huán)境下進行共享,而不需要額外的同步開銷

總結(jié)

  • final 關(guān)鍵字可以用于成員變量、本地變量、方法以及類

  • final 成員變量必須在聲明的時候初始化或者在構(gòu)造器中初始化,否則就匯報編譯錯誤

  • 不能夠?qū)?final 變量再次賦值

  • 本地變量必須在聲明時賦值

  • 在匿名類中所有變量都必須是 final 變量

  • final 方法不能被重寫

  • final 類不能被繼承

  • 接口中聲明的所有變量本身是 final 的

  • final 和 abstract 這兩個關(guān)鍵字是反相關(guān)的,final 類就不可能是 abstract 的

  • 沒有在聲明時初始化 final 變量的稱為空白 final 變量(blank final variable),它們必須在構(gòu)造器中初始化,或者調(diào)用 this() 初始化,不這么做的話,編譯器會報錯final變量(變量名)需要進行初始化

  • 按照 Java 代碼慣例,final 變量就是常量,而且通常常量名要大寫

  • 對于集合對象聲明為 final 指的是引用不能被更改

到此,相信大家對“Java中final關(guān)鍵字的原理和應(yīng)用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI