小議Java中final關(guān)鍵字使用時(shí)的注意點(diǎn)
final 類
final 類不能被繼承,同時(shí),一旦用 final 修飾了類,也就意味著 final 類中的所有方法都被隱式地指定為 final 方法
final 方法
在類繼承的過程中,對于父類中的 final 方法,子類不能修改和覆蓋。
private 方法都被隱式指定為 final 方法。
有兩個(gè)原因使用 final 方法:
- 鎖定方法,防止被子類修改其含義
- 在早期的 java 實(shí)現(xiàn)版本中,final 方法被實(shí)現(xiàn)為內(nèi)嵌調(diào)用,可以提升性能
final 變量
final 關(guān)鍵字用來修飾變量是最常用的用法,如果修飾成員變量,則必須在定義時(shí)或者構(gòu)造方法中初始化,且一經(jīng)初始化此后不能再進(jìn)行任何賦值。
針對基本類型和類對象有著不同的含義:
- 對于基本類型,final 變量一經(jīng)初始化,此后不能再改變該變量的值
- 對于類對象,已經(jīng)初始化后,不能讓這個(gè)變量再指向另一個(gè)對象,但他指向的對象的內(nèi)容是可以改變的
static final 域稱為編譯期常量,一般全部大寫。
示例
class Glyph { void draw() { System.out.println("Glyph.draw()"); } Glyph() { System.out.println("Glyph() before draw()"); draw(); System.out.println("Glyph() after draw()"); } } class RoundGlyph extends Glyph { private int redius = 1; RoundGlyph(int r) { radius = r; System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius); } void draw() { System.out.println("RoundGlyph.draw(), radius = " + radius); } } public class RolyConstructors { public static void main(String[] args) { new RoundGlyph(5); } }
輸出結(jié)果:
Glyph() before draw() RoundGlyph.draw(), radius = 0 Glyph() after draw() RoundGlyph.RoundGlyph(), radius = 5
上面的代碼展示了類初始化過程以及隱藏的災(zāi)難性問題。
main 函數(shù)中以參數(shù) 5 調(diào)用 RoundGlyph 的構(gòu)造函數(shù)創(chuàng)建了 RoundGlyph 對象,在 RoundGlyph 構(gòu)造方法執(zhí)行前調(diào)用了其父類 Glyph 的構(gòu)造方法。
然而,在父類 Glyph 的構(gòu)造方法中調(diào)用了 draw 方法,由于多態(tài)性,此時(shí)實(shí)際上調(diào)用了子類的 draw 方法,然而子類的 redius 此時(shí)還沒有通過構(gòu)造器初始化,因此輸出了:
RoundGlyph.draw(), radius = 0
這顯然不是我們想要的結(jié)果,因此需要注意:
- 用盡可能簡單的方法初始化類成員
- 在構(gòu)造器中最好只調(diào)用 final 方法
第二條的原因是 final 不會應(yīng)用多態(tài)性,因此可以保證調(diào)用的是當(dāng)前對象的相應(yīng)方法,而不是初始化工作還沒有進(jìn)行的子類的覆蓋方法。
總結(jié)final的內(nèi)存分配方式:
1.修飾變量:
通常情況下,final變量有3個(gè)地方可以賦值:直接賦值,構(gòu)造函數(shù)中,或是初始化塊中。
(1)初始化:
由于在java的語法中,聲明和初始化是聯(lián)系在一起的,
也就是說:如果你不顯示的初始化一個(gè)變量,系統(tǒng)會自動(dòng)用一個(gè)默認(rèn)值來對其進(jìn)行初始化。(如int就是0)
對于final變量,在聲明時(shí),如果你沒有賦值,系統(tǒng)默認(rèn)這是一個(gè)空白域,在構(gòu)造函數(shù)進(jìn)行初始化,
如果是靜態(tài)的,則可以在初始化塊。
(2)內(nèi)存:
常量(final變量)和非final變量的處理方式是不一樣的。
每一個(gè)類型在用到一個(gè)常量時(shí),都會復(fù)制一份到自己的常量池中。
常量也像類變量(static)一樣保存在方法區(qū),只不過他保存在常量池。
(可能是,類變量被所有實(shí)例共享,而常量池是每個(gè)實(shí)例獨(dú)有的。)
2.修飾方法:
保存在方法區(qū),并且可以被函數(shù)代碼直接替換,而不用等到執(zhí)行時(shí)再?zèng)Q定具體是那個(gè)函數(shù)。
3.修飾類:
保存在方法區(qū)。
相關(guān)文章
java HttpClient傳輸json格式的參數(shù)實(shí)例講解
這篇文章主要介紹了java HttpClient傳輸json格式的參數(shù)實(shí)例講解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01Java 基礎(chǔ)全面講解StringBuffer類的使用
當(dāng)對字符串進(jìn)行修改的時(shí)候,需要使用 StringBuffer 和 StringBuilder類,和String類不同的是,StringBuffer和 StringBuilder類的對象能夠被多次的修改,并且不產(chǎn)生新的未使用對象2022-01-01Java并發(fā)編程線程間通訊實(shí)現(xiàn)過程詳解
這篇文章主要介紹了Java并發(fā)編程線程間通訊實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05SpringBoot?實(shí)現(xiàn)微信推送模板的示例代碼
這篇文章主要介紹了SpringBoot?實(shí)現(xiàn)微信推送模板,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12Spring MVC---數(shù)據(jù)綁定和表單標(biāo)簽詳解
本篇文章主要介紹了Spring MVC---數(shù)據(jù)綁定和表單標(biāo)簽詳解,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01Java連接MYSQL數(shù)據(jù)庫的實(shí)現(xiàn)步驟
以下的文章主要描述的是java連接MYSQL數(shù)據(jù)庫的正確操作步驟,在此篇文章里我們主要是以實(shí)例列舉的方式來引出其具體介紹2013-06-06Java中關(guān)于內(nèi)存泄漏出現(xiàn)的原因匯總及如何避免內(nèi)存泄漏(超詳細(xì)版)
這篇文章主要介紹了Java中關(guān)于內(nèi)存泄漏出現(xiàn)的原因匯總及如何避免內(nèi)存泄漏(超詳細(xì)版)的相關(guān)資料,需要的朋友可以參考下2016-09-09