閱讀經(jīng)典——《Effective Java》03
Java語言包中的Object類是所有類的祖先身腻。該類提供了諸如equals产还、hashCode、toString嘀趟、clone脐区、finalize等方法。本文重點(diǎn)討論finalize方法她按,其余將在后面文章中陸續(xù)出現(xiàn)牛隅。
finalize方法
Java文檔對(duì)finalize方法的解釋如下。
當(dāng)對(duì)象不再擁有可到達(dá)的引用時(shí)酌泰,垃圾回收器在回收該對(duì)象的空間前調(diào)用它的finalize方法媒佣。子類可在該方法中釋放占用的系統(tǒng)資源或執(zhí)行其它清理工作。
通常陵刹,我們會(huì)用finalize方法關(guān)閉已經(jīng)打開的文件默伍,但是請(qǐng)注意,這是嚴(yán)重錯(cuò)誤授霸!
finalize方法的缺點(diǎn)在于不保證會(huì)被及時(shí)的執(zhí)行巡验,甚至根本不保證一定會(huì)執(zhí)行。很多時(shí)候直到程序終止仍然有不可達(dá)對(duì)象的finalize方法沒有被執(zhí)行碘耳。因此,在finalize中關(guān)閉文件很可能失敗框弛。
另外辛辨,System.gc()
和System.runFinalization()
只是增加finalize被執(zhí)行的機(jī)會(huì)。唯一聲稱保證finalize方法在程序終止前執(zhí)行的是System.runFinalizersOnExit
和Runtime.runFinalizersOnExit
瑟枫。但它們有致命的缺陷斗搞,已經(jīng)被廢棄了。
finalize中拋出的異常會(huì)被忽略慷妙,以至于程序員無法得知它是否成功執(zhí)行僻焚。
finalize會(huì)導(dǎo)致嚴(yán)重的性能損失(在原書作者的機(jī)器上,有finalize方法時(shí)創(chuàng)建和銷毀對(duì)象慢了大約430倍)膝擂。
因此虑啤,鑒于finalize方法有如此多的缺點(diǎn)隙弛,我們大部分時(shí)候應(yīng)當(dāng)避免使用。但仍有兩種合理用法狞山。
用途一:配合顯式終止方法
仍然是關(guān)閉文件的問題全闷,正確的做法是提供一個(gè)顯式終止方法,通常稱為close
萍启,并要求客戶端程序手動(dòng)調(diào)用总珠。該方案的典型例子是InputStream
、OutputStream
勘纯、java.sql.Connection
局服,這些類都提供了close
方法以關(guān)閉相應(yīng)的文件或數(shù)據(jù)庫連接。
但是一些不靠譜的程序員通常會(huì)忘記調(diào)用close
方法驳遵,因此可以在finalize中再次檢查并調(diào)用close
方法腌逢,以降低資源泄漏的可能性。(注意超埋,由于finalize并不可靠搏讶,該方案只能降低資源泄漏的可能性而無法完全消除。)在InputStream
霍殴、OutputStream
媒惕、java.sql.Connection
這些類中也的確是這樣做的,大家可以自己查看源碼来庭。
用途二:終結(jié)方法守衛(wèi)者
如果子類打算重寫父類的finalize方法妒蔚,我們推薦以下面的方式重寫。這樣做可以保證即使子類的終結(jié)過程拋出異常月弛,父類的finalize方法也會(huì)得到執(zhí)行肴盏。
@Override
protected void finalize() throws Throwable {
try {
//Finalize subclass state
} finally {
super.finalize();
}
}
但是,假如子類沒有在重寫的finalize方法中調(diào)用super.finalize()
帽衙,那么父類的finalize方法將永遠(yuǎn)不能得到調(diào)用菜皂。站在父類的角度上,要想防范這樣粗心或者惡意的子類厉萝,可以使用終結(jié)方法守衛(wèi)者恍飘。
終結(jié)方法守衛(wèi)者是在父類中的一個(gè)匿名內(nèi)部類實(shí)例,該內(nèi)部類覆寫finalize方法谴垫,并在其中做父類需要的終結(jié)操作章母。
public class Foo {
private final Object finalizerGuardian = new Object() {
@Override
protected void finalize() throws Throwable {
//Finalize outer Foo object
}
};
//...
}
現(xiàn)在,即使Foo的子類覆寫了finalize方法翩剪,也不會(huì)影響Foo的終結(jié)操作乳怎,因?yàn)?code>finalizerGuardian一直存在。當(dāng)子類對(duì)象不可達(dá)時(shí)前弯,finalizerGuardian
同樣不可達(dá)蚪缀,它們都會(huì)進(jìn)入垃圾回收器的回收隊(duì)列秫逝。因此可以保證父類的終結(jié)操作不被忽略。
關(guān)注作者或文集《Effective Java》椿胯,第一時(shí)間獲取最新發(fā)布文章筷登。
參考資料
Java終結(jié)方法的使用(終結(jié)守衛(wèi)者) SamXCode
What's the behaviors of fields when finalize an object? jinge
Java將棄用finalize()方法? Ben Evans