转 Java中final、finally、finalize的区别与用法
Java中final、finally、finalize的區(qū)別與用法
1.簡(jiǎn)單區(qū)別:
final用于聲明屬性,方法和類,分別表示屬性不可交變,方法不可覆蓋,類不可繼承。
finally是異常處理語(yǔ)句結(jié)構(gòu)的一部分,表示總是執(zhí)行。
finalize是Object類的一個(gè)方法,在垃圾收集器執(zhí)行的時(shí)候會(huì)調(diào)用被回收對(duì)象的此方法,供垃圾收集時(shí)的其他資源回收,例如關(guān)閉文件等。
2.中等區(qū)別:
雖然這個(gè)單詞在Java中都存在,但是并沒太多關(guān)聯(lián):
final:java中的關(guān)鍵字,修飾符。
A).如果一個(gè)類被聲明為final,就意味著它不能再派生出新的子類,不能作為父類被繼承。因此,一個(gè)類不能同時(shí)被聲明為abstract抽象類的和final的類。
B).如果將變量或者方法聲明為final,可以保證它們?cè)谑褂弥胁槐桓淖?
1)被聲明為final的變量必須在聲明時(shí)給定初值,而在以后的引用中只能讀取,不可修改。
2)被聲明final的方法只能使用,不能重載。
finally:java的一種異常處理機(jī)制。
finally是對(duì)Java異常處理模型的最佳補(bǔ)充。finally結(jié)構(gòu)使代碼總會(huì)執(zhí)行,而不管無(wú)異常發(fā)生。使用finally可以維護(hù)對(duì)象的內(nèi)部狀態(tài),并可以清理非內(nèi)存資源。特別是在關(guān)閉數(shù)據(jù)庫(kù)連接這方面,如果程序員把數(shù)據(jù)庫(kù)連接的close()方法放到finally中,就會(huì)大大降低程序出錯(cuò)的幾率。
finalize:Java中的一個(gè)方法名。
Java技術(shù)使用finalize()方法在垃圾收集器將對(duì)象從內(nèi)存中清除出去前,做必要的清理工作。這個(gè)方法是由垃圾收集器在確定這個(gè)對(duì)象沒被引用時(shí)對(duì)這個(gè)對(duì)象調(diào)用的。它是在Object類中定義的,因此所的類都繼承了它。子類覆蓋finalize()方法以整理系統(tǒng)資源或者執(zhí)行其他清理工作。finalize()方法是在垃圾收集器刪除對(duì)象之前對(duì)這個(gè)對(duì)象調(diào)用的。
3.詳細(xì)區(qū)別:
這是一道再經(jīng)典不過(guò)的面試題了,我們?cè)诟鱾€(gè)公司的面試題中幾乎都能看到它的身影。final、finally和finalize雖然長(zhǎng)得像孿生兄弟一樣,但是它們的含義和用法卻是大相徑庭。
final關(guān)鍵字我們首先來(lái)說(shuō)說(shuō)final。它可以用于以下四個(gè)地方:
1).定義變量,包括靜態(tài)的和非靜態(tài)的。
2).定義方法的參數(shù)。
3).定義方法。
4).定義類。
定義變量,包括靜態(tài)的和非靜態(tài)的。定義方法的參數(shù)
第一種情況:
??如果final修飾的是一個(gè)基本類型,就表示這個(gè)變量被賦予的值是不可變的,即它是個(gè)常量;
??如果final修飾的是一個(gè)對(duì)象,就表示這個(gè)變量被賦予的引用是不可變的
這里需要提醒大家注意的是,不可改變的只是這個(gè)變量所保存的引用,并不是這個(gè)引用所指向的對(duì)象。
第二種情況:final的含義與第一種情況相同。
實(shí)際上對(duì)于前兩種情況,一種更貼切的表述final的含義的描述,那就是,如果一個(gè)變量或方法參數(shù)被final修飾,就表示它只能被賦值一次,但是JAVA虛擬機(jī)為變量設(shè)定的默認(rèn)值不記作一次賦值。被final修飾的變量必須被初始化。初始化的方式以下幾種:????
1.在定義的時(shí)候初始化。????
2.final變量可以在初始化塊中初始化,不可以在靜態(tài)初始化塊中初始化。
3.靜態(tài)final變量可以在定義時(shí)初始化,也可以在靜態(tài)初始化塊中初始化,不可以在初始化塊中初始化。????
4.final變量還可以在類的構(gòu)造器中初始化,但是靜態(tài)final變量不可以。
通過(guò)下面的代碼可以驗(yàn)證以上的觀點(diǎn):
我們運(yùn)行上面的代碼之后出了可以發(fā)現(xiàn)final變量(常量和靜態(tài)final變量(靜態(tài)常量被初始化時(shí),編譯會(huì)報(bào)錯(cuò)。
用final修飾的變量(常量比非final的變量(普通變量擁更高的效率,因此我們?cè)陔H編程中應(yīng)該盡可能多的用常量來(lái)代替普通變量。
定義方法
當(dāng)final用來(lái)定義一個(gè)方法時(shí),它表示這個(gè)方法不可以被子類重寫,但是并不影響它被子類繼承。我們寫段代碼來(lái)驗(yàn)證一下:
這里需要特殊說(shuō)明的是,具有private訪問(wèn)權(quán)限的方法也可以增加final修飾,但是由于子類無(wú)法繼承private方法,因此也無(wú)法重寫它。編譯器在處理private方法時(shí),是照f(shuō)inal方來(lái)對(duì)待的,這樣可以提高該方法被調(diào)用時(shí)的效率。不過(guò)子類仍然可以定義同父類中private方法具同樣結(jié)構(gòu)的方法,但是這并不會(huì)產(chǎn)生重寫的效果,而且它們之間也不存在必然聯(lián)系。
定義類
最后我們?cè)賮?lái)回顧一下final用于類的情況。這個(gè)大家應(yīng)該也很熟悉了,因?yàn)槲覀冏畛S玫腟tring類就是final的。由于final類不允許被繼承,編譯器在處理時(shí)把它的所方法都當(dāng)作final的,因此final類比普通類擁更高的效率。而由關(guān)鍵字abstract定義的抽象類含必須由繼承自它的子類重載實(shí)現(xiàn)的抽象方法,因此無(wú)法同時(shí)用final和abstract來(lái)修飾同一個(gè)類。同樣的道理,
final也不能用來(lái)修飾接口。?final的類的所方法都不能被重寫,但這并不表示final的類的屬性(變量值也是不可改變的,要想做到final類的屬性值不可改變,必須給它增加final修飾,請(qǐng)看下面的例子:
運(yùn)行上面的代碼試試看,結(jié)果是99,而不是初始化時(shí)的10。
finally語(yǔ)句
接下來(lái)我們一起回顧一下finally的用法。finally只能用在try/catch語(yǔ)句中并且附帶著一個(gè)語(yǔ)句塊,表示這段語(yǔ)句最終總是被執(zhí)行。請(qǐng)看下面的代碼:
運(yùn)行結(jié)果說(shuō)明了finally的作用:
1.程序拋出了異常
2.執(zhí)行了finally語(yǔ)句塊請(qǐng)大家注意,捕獲程序拋出的異常之后,既不加處理,也不繼續(xù)向上拋出異常,并不是良好的編程習(xí)慣,它掩蓋了程序執(zhí)行中發(fā)生的錯(cuò)誤,這里只是方便演示,請(qǐng)不要學(xué)習(xí)。
那么,沒一種情況使finally語(yǔ)句塊得不到執(zhí)行呢?
return、continue、break這個(gè)可以打亂代碼順序執(zhí)行語(yǔ)句的規(guī)律。那我們就來(lái)試試看,這個(gè)語(yǔ)句是否能影響finally語(yǔ)句塊的執(zhí)行:
很明顯,return、continue和break都沒能阻止finally語(yǔ)句塊的執(zhí)行。從輸出的結(jié)果來(lái)看,return語(yǔ)句似乎在finally語(yǔ)句塊之前執(zhí)行了,事實(shí)真的如此嗎?我們來(lái)想想看,return語(yǔ)句的作用是什么呢?是退出當(dāng)前的方法,并將值或?qū)ο蠓祷亍H绻?finally語(yǔ)句塊是在return語(yǔ)句之后執(zhí)行的,那么return語(yǔ)句被執(zhí)行后就已經(jīng)退出當(dāng)前方法了,finally語(yǔ)句塊又如何能被執(zhí)行呢?因此,正確的執(zhí)行順序應(yīng)該是這樣的:編譯器在編譯return new ReturnClass();時(shí),將它分成了兩個(gè)步驟,new ReturnClass()和return,前一個(gè)創(chuàng)建對(duì)象的語(yǔ)句是在finally語(yǔ)句塊之前被執(zhí)行的,而后一個(gè)return語(yǔ)句是在finally語(yǔ)句塊之后執(zhí)行的,也就是說(shuō)finally語(yǔ)句塊是在程序退出方法之前被執(zhí)行的。同樣,finally語(yǔ)句塊是在循環(huán)被跳過(guò)(continue和中斷(break之前被執(zhí)行的
finalize方法
最后,我們?cè)賮?lái)看看finalize,它是一個(gè)方法,屬于java.lang.Object類,它的定義如下:protected void finalize()throws Throwable{}眾所周知,finalize()方法是GC(garbagecollector運(yùn)行機(jī)制的一部分,在此我們只說(shuō)說(shuō)finalize()方法的作用是什么呢?finalize()方法是在GC清理它所從屬的對(duì)象時(shí)被調(diào)用的,如果執(zhí)行它的過(guò)程中拋出了無(wú)法捕獲的異常(uncaughtexception,GC將終止對(duì)改對(duì)象的清理,并且該異常會(huì)被忽略;直到下一次GC開始清理這個(gè)對(duì)象時(shí),它的finalize()會(huì)被再次調(diào)用。請(qǐng)看下面的示例:
運(yùn)行結(jié)果如下:??執(zhí)行了finalize()方法
程序調(diào)用了java.lang.System類的gc()方法,引起GC的執(zhí)行,GC在清理ft對(duì)象時(shí)調(diào)用了它的finalize()方法,因此才了上面的輸出結(jié)果。調(diào)用System.gc()等同于調(diào)用下面這行代碼:Runtime.getRuntime().gc();調(diào)用它們的作用只是建議垃圾收集器(GC啟動(dòng),清理無(wú)用的對(duì)象釋放內(nèi)存空間,但是GC的啟動(dòng)并不是一定的,這由JAVA虛擬機(jī)來(lái)決定。直到?JAVA虛擬機(jī)停止運(yùn)行,些對(duì)象的finalize()可能都沒被運(yùn)行過(guò),那么怎樣保證所對(duì)象的這個(gè)方法在JAVA虛擬機(jī)停止運(yùn)行之前一定被調(diào)用呢?答案是我們可以調(diào)用System類的另一個(gè)方法:
給這個(gè)方法傳入true就可以保證對(duì)象的finalize()方法在JAVA虛擬機(jī)停止運(yùn)行前一定被運(yùn)行了,不過(guò)遺憾的是這個(gè)方法是不安全的,它會(huì)導(dǎo)致有用的對(duì)象finalize()被誤調(diào)用,因此已不被贊成使用了。由于finalize()屬于Object類,因此所類都這個(gè)方法,Object的任意子類都可以重寫(override該方法,在其中釋放系統(tǒng)資源或者做其它的清理工作,如關(guān)閉輸入輸出流。通過(guò)以上知識(shí)的回顧,我想大家對(duì)于final、finally、finalize的用法區(qū)別已經(jīng)很清楚了。
轉(zhuǎn)載于:https://www.cnblogs.com/mytzq/p/11125888.html
總結(jié)
以上是生活随笔為你收集整理的转 Java中final、finally、finalize的区别与用法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Git push “fatal: Aut
- 下一篇: java -PDF添加文本水印与图片水印