目錄
五、final原理
首頁 Java java教程 Java中final實作原理的深入分析(附範例)

Java中final實作原理的深入分析(附範例)

Nov 27, 2018 pm 04:56 PM
final

這篇文章帶給大家的內容是關於Java中final實現原理的深入分析(附範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

final在Java中是一個保留的關鍵字,可以宣告成員變數、方法、類別以及本地變數。

一旦你將引用宣告作final,你將不能改變這個引用了,編譯器會檢查程式碼,如果你試圖將變數再次初始化的話,編譯器會報編譯錯誤。

一、final變數

final成員變數表示常數,只能被賦值一次,賦值後值不再改變(final要求位址值不能改變)

當final修飾一個基本資料型別時,表示該基本資料型別的值一旦在初始化後便不能改變;如果final修飾一個參考型別時,則在對其初始化之後便不能再讓其指向其他物件了,但該引用所指向的物件的內容是可以改變的。本質上是一回事,因為引用的值是一個位址,final要求值,即位址的值不會改變。

final修飾一個成員變數(屬性),必須顯示初始化。這裡有兩種初始化方式,一種是在變數宣告的時候初始化;第二種方法是在宣告變數的時候不賦初值,但是要在這個變數所在的類別的所有的建構子中對這個變數賦初值。

二、final方法

使用final方法的原因有兩個。

第一個原因是把方法鎖定,以防任何繼承類別修改它的意義,不能被重寫;

第二個原因是效率,final方法比非final方法要快,因為在編譯的時候已經靜態綁定了,不需要在執行時再動態綁定。

(註:類別的private方法會隱式地被指定為final方法)

#三、final類別

當用final修飾一個類別時,表示這個類別不能被繼承。

final類別中的成員變數可以根據需要設為final,但是要注意final類別中的所有成員方法都會被隱含地指定為final方法。

在使用final修飾類別的時候,要注意謹慎選擇,除非這個類別真的在以後不會用來繼承或出於安全的考慮,盡量不要將類別設計為final類別。

四、final使用總結

#final關鍵字的優點:

#(1)final關鍵字提高了效能。 JVM和Java應用程式都會快取final變數。

(2)final變數可以安全的在多執行緒環境下進行共享,而不需要額外的同步開銷。

(3)使用final關鍵字,JVM會對方法、變數及類別進行最佳化。

關於final的重要知識點

1、final關鍵字可以用於成員變數、本地變數、方法以及類別。

2、final成員變數必須在宣告的時候初始化或是在建構器中初始化,否則就會報編譯錯誤。

3、你不能夠對final變數再次賦值。

4、本機變數必須在宣告時賦值。

5、在匿名類別中所有變數都必須是final變數。

6、final方法不能被重寫。

7、final類別不能被繼承。

8、final關鍵字不同於finally關鍵字,後者用於例外處理。

9、final關鍵字容易與finalize()方法搞混,後者是在Object類別中定義的方法,是在垃圾回收之前被JVM呼叫的方法。

10、介面中宣告的所有變數本身都是final的。

11、final和abstract這兩個關鍵字是反相關的,final類別就不可能是abstract的。

12、final方法在編譯階段綁定,稱為靜態綁定(static binding)。

13、沒有在宣告時初始化final變數的稱為空白final變數(blank final variable),它們必須在建構器中初始化,或是呼叫this()初始化。不這麼做的話,編譯器會報錯「final變數(變數名)需要初始化」。

14、將類別、方法、變數宣告為final能夠提高效能,這樣JVM就有機會進行估計,然後最佳化。

15、依照Java程式碼慣例,final變數就是常數,而且通常常數名稱要大寫。

16、對於集合物件宣告為final指的是引用不能被更改,但是你可以往其中增加,刪除或改變內容。

五、final原理

最好先理解java記憶體模型 Java並發(二):Java記憶體模型

對於final域,編譯器和處理器要遵守兩個重排序規則:

1.在建構子內對一個final域的寫入,與隨後把這個被建構物件的引用賦值給一個引用變量,這兩個運算之間不能重新排序。

(先寫入final變量,後呼叫該物件參考)

原因:編譯器會在final域的寫入之後,插入一個StoreStore屏障

2.初次讀一個包含final域的物件的引用,與隨後初次讀這個final域,這兩個運算之間不能重新排序。

(先讀物件的引用,後讀final變數)

編譯器會在讀取final域操作的前面插入一個LoadLoad屏障 

範例1:

public class FinalExample {
    int i; // 普通变量
    final int j; // final 变量
    static FinalExample obj;
    public void FinalExample() { // 构造函数
        i = 1; // 写普通域
        j = 2; // 写 final 域
    }
    public static void writer() { // 写线程 A 执行
        obj = new FinalExample();
    }
    public static void reader() { // 读线程 B 执行
        FinalExample object = obj; // 读对象引用
        int a = object.i; // 读普通域         a=1或者a=0或者直接报错i没有初始化
        int b = object.j; // 读 final域      b=2
    }
}
登入後複製

第一種情況:寫普通域的操作被編譯器重新排序到了構造函數之外

而寫final 域的操作,被寫final域的重排序規則「限定」在了建構函式之內,讀出線程B 正確的讀取了final 變數初始化之後的值。

寫入 final 域的重新排序規則可以確保:在物件引用為任意執行緒可見之前,物件的 final 域已經被正確初始化過了,而普通域不具有這個保障。

第二種情況:讀取物件的普通域的操作被處理器重排序到讀取物件引用之前

而讀final 域的重排序規則會把讀取物件final 域的操作「限定」在讀取物件參考之後,此時該final 域已經被A 執行緒初始化過了,這是一個正確的讀取操作。

讀取 final 域的重新排序規則可以確保:在讀一個物件的 final 域之前,一定會先讀出包含這個 final 域的物件的參考。

 

 

範例2:如果final 域是引用型別

對於引用類型,寫final 域的重新排序規則對編譯器和處理器增加瞭如下約束:

在構造函數內對一個final 引用的對象的成員域的寫入,與隨後在構造函數外把這個被構造對象的引用賦值給一個引用變量,這兩個操作之間不能重新排序。

public class FinalReferenceExample {
    final int[] intArray; // final 是引用类型
    static FinalReferenceExample obj;
    public FinalReferenceExample() { // 构造函数
        intArray = new int[1]; // 1
        intArray[0] = 1; // 2
    }
    public static void writerOne() { // 写线程 A 执行
        obj = new FinalReferenceExample(); // 3
    }
    public static void writerTwo() { // 写线程 B 执行
        obj.intArray[0] = 2; // 4
    }
    public static void reader() { // 读线程 C 执行
        if (obj != null) { // 5
            int temp1 = obj.intArray[0]; // 6  temp1=1或者temp1=2,不可能等于0
        }
    }
}
登入後複製

 假設先執行緒 A 執行 writerOne() 方法,執行完後執行緒 B 執行 writerTwo() 方法,執行完後執行緒 C 執行 reader () 方法。

 

在上圖中,1 是對final 域的寫入,2 是對這個final 域所引用的物件的成員域的寫入,3 是把被建構的物件的引用賦值給某個引用變數。這裡除了前面提到的 1 不能和 3 重排序外,2 和 3 也不能重新排序。

JMM 可以確保讀取線程 C 至少能看到寫線程 A 在建構子中對 final 引用物件的成員域的寫入。即 C 至少能看到數組下標 0 的值為 1。而寫線程 B 對數組元素的寫入,讀線程 C 可能看的到,也可能看不到。 JMM 不保證執行緒 B 的寫入對讀執行緒 C 可見,因為寫執行緒 B 和讀取執行緒 C 之間存在資料競爭,此時的執行結果不可預測。

以上是Java中final實作原理的深入分析(附範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Java中final、finally、finalize的區別 Java中final、finally、finalize的區別 Feb 19, 2024 pm 12:16 PM

Java中final、finally、finalize的區別,需要具體程式碼範例在Java程式設計中,經常會遇到final、finally、finalize這三個關鍵字,它們雖然拼字相似,但卻有不同的意思和用法。本文將詳細解釋這三個關鍵字的區別,同時給出程式碼範例以幫助讀者更好地理解。一、final關鍵字final關鍵字可以用於類別、方法和變數。它的作用是使被修飾的類

在Java中,僅使用final關鍵字可以定義一個常數嗎? 在Java中,僅使用final關鍵字可以定義一個常數嗎? Sep 20, 2023 pm 04:17 PM

常量變數是其值固定且程式中只存在一個副本的變數。一旦你聲明了一個常數變數並給它賦值,你就不能在整個程式中再次改變它的值。與其他語言不同,Java不直接支援常數。但是,你仍然可以透過宣告一個變數為靜態和final來創建一個常數。靜態-一旦你聲明了一個靜態變量,它們將在編譯時加載到內存中,即只有一個副本可用。 Final-一旦你宣告了一個final變量,就不能再修改它的值。因此,你可以透過將實例變數宣告為靜態和final來在Java中創建一個常數。範例 示範classData{&am

java final關鍵字的作用是什麼 java final關鍵字的作用是什麼 Nov 25, 2022 pm 04:26 PM

在java中,final可以用來修飾類別、方法和變數。 final修飾類,表示該類是無法被任何其他類繼承的,意味著此類在一個繼承樹中是一個葉子類,並且此類的設計已被認為很完美而不需要進行修改或擴展。 final修飾類別中的方法,表示該類別是無法被任何其他類別繼承的,不可以被重寫;也就是把該方法鎖定了,以防止繼承類別對其進行更改。 final修飾類別中的變量,表示該變數一旦被初始化就不可改變。

Java中final物件的創建方式是什麼? Java中final物件的創建方式是什麼? Apr 11, 2024 pm 02:00 PM

Java中建立final物件有兩種方法:宣告final變數或使用final修飾符宣告類別。宣告final變數時,物件透過初始化器建立;宣告final類別時,該類別實例不可變。重要的是,final物件的引用仍然可以改變,但它們指向的物件不可變。

Java中的最終變數 Java中的最終變數 Sep 24, 2023 pm 08:49 PM

最終變數只能明確初始化一次。宣告為Final的引用變數永遠不能重新指派以引用不同的物件。但是,物件內的資料是可以更改的。因此,物件的狀態可以更改,但引用不能更改。對於變量,final修飾符通常與static一起使用以使常數成為類別變量。範例publicclassTest{  finalintvalue=10;  //Thefollowingareexamplesofdeclaringconstants: &a

PHP中的特殊語法:Static、Final、Abstract等關鍵字 PHP中的特殊語法:Static、Final、Abstract等關鍵字 May 11, 2023 pm 04:00 PM

PHP是一種流行的開源伺服器端腳本語言,廣泛應用於Web開發。 PHP語言不僅易於學習和使用,而且支援多種程式設計範例、物件導向的程式設計和函數式程式設計等。在PHP中,有一些特殊的語法關鍵字,如Static、Final、Abstract等,這些關鍵字在物件導向程式設計中具有特殊的作用。本文將對這些關鍵字進行詳細介紹。 Static關鍵字在PHP中,Static關鍵字有兩種用法

Java錯誤:濫用final關鍵字,如何解決與避免 Java錯誤:濫用final關鍵字,如何解決與避免 Jun 24, 2023 pm 09:00 PM

Java作為十分流行的程式語言,運用廣泛,被廣泛應用於互聯網、行動裝置等領域。對Java開發者來說,常常會遇到一些錯誤或問題,其中一個就是濫用final關鍵字。在Java中,final關鍵字經常被用來修飾變數、方法、類別等,它表示該屬性在定義之後不可再改變。 final關鍵字可以幫助開發者保證物件的不可變性、避免競態條件等問題,但濫用final關鍵字

為什麼在Java中構造函式不能是final的? 為什麼在Java中構造函式不能是final的? Aug 20, 2023 pm 07:01 PM

每當你將一個方法宣告為final時,你就不能覆寫它。也就是說,你不能為子類別提供超類別的final方法的實作。也就是說,將一個方法宣告為final的目的是防止從外部(子類別)修改該方法。在繼承中,當你擴展一個類別時,子類別會繼承超類別的所有成員,除了建構子。換句話說,構造函數不能在Java中被繼承,因此你不能覆蓋構造函數。因此,在建構子前面加上final沒有意義。因此,Java不允許在建構函式前使用final關鍵字。如果你嘗試將建構函式宣告為final,將會產生一個編譯時錯誤,提示「modifierf

See all articles