java finalize方法的使用
《JAVA編程思想》:
Java提供finalize()方法,垃圾回收器準(zhǔn)備釋放內(nèi)存的時(shí)候,會(huì)先調(diào)用finalize()。
????????? (1).對象不一定會(huì)被回收。
?????? (2).垃圾回收不是析構(gòu)函數(shù)。
?????? (3).垃圾回收只與內(nèi)存有關(guān)。
?????? (4).垃圾回收和finalize()都是靠不住的,只要JVM還沒有快到耗盡內(nèi)存的地步,它是不會(huì)浪費(fèi)時(shí)間進(jìn)行垃圾回收的。
有時(shí)當(dāng)撤消一個(gè)對象時(shí),需要完成一些操作。例如,如果一個(gè)對象正在處理的是非Java 資源,如文件句柄或window 字符字體,這時(shí)你要確認(rèn)在一個(gè)對象被撤消以前要保證這些資源被釋放。為處理這樣的狀況,Java 提供了被稱為收尾(finalization )的機(jī)制。使用該機(jī)制你可以定義一些特殊的操作,這些操作在一個(gè)對象將要被垃圾回收程序釋放時(shí)執(zhí)行。
要給一個(gè)類增加收尾(finalizer ),你只要定義finalize ( ) 方法即可。Java 回收該類的一個(gè)對象時(shí),就會(huì)調(diào)用這個(gè)方法。在finalize ( )方法中,你要指定在一個(gè)對象被撤消前必須執(zhí)行的操作。垃圾回收周期性地運(yùn)行,檢查對象不再被運(yùn)行狀態(tài)引用或間接地通過其他對象引用。就在對象被釋放之前,Java 運(yùn)行系統(tǒng)調(diào)用該對象的finalize( ) 方法。
finalize()方法的通用格式如下:
protected void finalize( )
{
// finalization code here
}
其中,關(guān)鍵字protected是防止在該類之外定義的代碼訪問finalize()標(biāo)識符。該標(biāo)識符和其他標(biāo)識符將在第7章中解釋。
理解finalize( ) 正好在垃圾回收以前被調(diào)用非常重要。例如當(dāng)一個(gè)對象超出了它的作用域時(shí),finalize( ) 并不被調(diào)用。這意味著你不可能知道何時(shí)——甚至是否——finalize( ) 被調(diào)用。因此,你的程序應(yīng)該提供其他的方法來釋放由對象使用的系統(tǒng)資源,而不能依靠finalize( ) 來完成程序的正常操作。
注意:如果你熟悉C ,那你知道C 允許你為一個(gè)類定義一個(gè)撤消函數(shù)(destructor ),它在對象正好出作用域之前被調(diào)用。Java不支持這個(gè)想法也不提供撤消函數(shù)。finalize() 方法只和撤消函數(shù)的功能接近。當(dāng)你對Java 有豐富經(jīng)驗(yàn)時(shí),你將看到因?yàn)镴ava使用垃圾回收子系統(tǒng),幾乎沒有必要使用撤消函數(shù)。
理解finalize()-析構(gòu)函數(shù)的替代者
by Tim Gooch
在許多方面,Java 類似于 C++。Java 的語法非常類似于 C++,Java 有類、方法和數(shù)據(jù)成員;Java 的類有構(gòu)造函數(shù); Java 有異常處理。
但是,如果你使用過 C++ 會(huì)發(fā)現(xiàn) Java 也丟掉一些可能是你熟悉的特性。這些特性之一就是析構(gòu)函數(shù)。取代使用析構(gòu)函數(shù),Java 支持finalize() 方法。
在本文中,我們將描述 finalize() 與 C++ 析構(gòu)函數(shù)的區(qū)別。另外,我們將創(chuàng)建一個(gè)簡單的 Applet 來演示 finalize() 是如何工作的。
最終的界限
與 Java 不同,C++ 支持局部對象(基于棧)和全局對象(基于堆)。因?yàn)檫@一雙重支持,C++ 也提供了自動(dòng)構(gòu)造和析構(gòu),這導(dǎo)致了對構(gòu)造函數(shù)和析構(gòu)函數(shù)的調(diào)用,(對于堆對象)就是內(nèi)存的分配和釋放。
在 Java 中,所有對象都駐留在堆內(nèi)存,因此局部對象就不存在。結(jié)果,Java 的設(shè)計(jì)者覺得不需要析構(gòu)函數(shù)(象 C++ 中所實(shí)現(xiàn)的)。
取而代之,Java 定義了一個(gè)特殊的方法叫做finalize() ,它提供了 C++ 析構(gòu)函數(shù)的一些功能。但是,finalize() 并不完全與 C++ 的析構(gòu)函數(shù)一樣,并可以假設(shè)它會(huì)導(dǎo)致一系列的問題。finalize() 方法作用的一個(gè)關(guān)鍵元素是 Java 的垃圾回收器。
垃圾回收器
在 C/C++、Pascal和其他幾種多種用途的編程語言中,開發(fā)者有責(zé)任在內(nèi)存管理上發(fā)揮積極的作用。例如,如果你為一個(gè)對象或數(shù)據(jù)結(jié)構(gòu)分配了內(nèi)存,那么當(dāng)你不再使用它時(shí)必須釋放掉該內(nèi)存。
在 Java 中,當(dāng)你創(chuàng)建一個(gè)對象時(shí),Java 虛擬機(jī)(JVM)為該對象分配內(nèi)存、調(diào)用構(gòu)造函數(shù)并開始跟蹤你使用的對象。當(dāng)你停止使用一個(gè)對象(就是說,當(dāng)沒有對該對象有效的引用時(shí)),JVM 通過垃圾回收器將該對象標(biāo)記為釋放狀態(tài)。
當(dāng)垃圾回收器將要釋放一個(gè)對象的內(nèi)存時(shí),它調(diào)用該對象的finalize() 方法(如果該對象定義了此方法)。垃圾回收器以獨(dú)立的低優(yōu)先級的方式運(yùn)行,只有當(dāng)其他線程掛起等待該內(nèi)存釋放的情況出現(xiàn)時(shí),它才開始運(yùn)行釋放對象的內(nèi)存。(事實(shí)上,你可以調(diào)用System.gc() 方法強(qiáng)制垃圾回收器來釋放這些對象的內(nèi)存。)
在以上的描述中,有一些重要的事情需要注意。首先,只有當(dāng)垃圾回收器釋放該對象的內(nèi)存時(shí),才會(huì)執(zhí)行finalize()。如果在 Applet 或應(yīng)用程序退出之前垃圾回收器沒有釋放內(nèi)存,垃圾回收器將不會(huì)調(diào)用finalize()。
其次,除非垃圾回收器認(rèn)為你的 Applet 或應(yīng)用程序需要額外的內(nèi)存,否則它不會(huì)試圖釋放不再使用的對象的內(nèi)存。換句話說,這是完全可能的:一個(gè) Applet 給少量的對象分配內(nèi)存,沒有造成嚴(yán)重的內(nèi)存需求,于是垃圾回收器沒有釋放這些對象的內(nèi)存就退出了。
顯然,如果你為某個(gè)對象定義了finalize() 方法,JVM 可能不會(huì)調(diào)用它,因?yàn)槔厥掌鞑辉尫胚^那些對象的內(nèi)存。調(diào)用System.gc() 也不會(huì)起作用,因?yàn)樗鼉H僅是給 JVM 一個(gè)建議而不是命令。
finalize() 有什么優(yōu)點(diǎn)呢?
如果finalize() 不是析構(gòu)函數(shù),JVM 不一定會(huì)調(diào)用它,你可能會(huì)疑惑它是否在任何情況下都有好處。事實(shí)上,在 Java 1.0 中它并沒有太多的優(yōu)點(diǎn)。
根據(jù) Java 文檔,finalize() 是一個(gè)用于釋放非 Java 資源的方法。但是,JVM 有很大的可能不調(diào)用對象的finalize() 方法,因此很難證明使用該方法釋放資源是有效的。
Java 1.1 通過提供一個(gè)System.runFinalizersOnExit() 方法部分地解決了這個(gè)問題。(不要將這個(gè)方法與 Java 1.0 中的System.runFinalizations() 方法相混淆。)不象System.gc() 方法那樣,System.runFinalizersOnExit() 方法并不立即試圖啟動(dòng)垃圾回收器。而是當(dāng)應(yīng)用程序或 Applet 退出時(shí),它調(diào)用每個(gè)對象的finalize() 方法。
正如你可能猜測的那樣,通過調(diào)用System.runFinalizersOnExit() 方法強(qiáng)制垃圾回收器清除所有獨(dú)立對象的內(nèi)存,當(dāng)清除代碼執(zhí)行時(shí)可能會(huì)引起明顯的延遲。現(xiàn)在建立一個(gè)示例 Applet 來演示 Java 垃圾回收器和finalize() 方法是如何相互作用的。
回收垃圾
通過使用Java Applet Wizard 創(chuàng)建一個(gè)新的 Applet 開始。當(dāng)提示這樣做時(shí),輸入final_things作為 Applet 名,并選擇不要生成源文件注釋。
接下來,在Java Applet Wizard 進(jìn)行第三步,不要選擇多線程選項(xiàng)。在第五步之前,根據(jù)需要修改 Applet 的描述。
當(dāng)你單擊Finish 后,Applet Wizard 將生成一個(gè)新的工作空間,并為該項(xiàng)目創(chuàng)建缺省的 Java 文件。從列表 A 中選擇適當(dāng)?shù)拇a輸入(我們已經(jīng)突出顯示了你需要輸入的代碼)。
當(dāng)你完成代碼的輸入后,配置Internet 瀏覽器將System.out 的輸出信息寫到Javalog.txt 文件中。(在IE 選項(xiàng)對話框的高級頁面中選擇起用 Java Logging。)
編譯并運(yùn)行該 Applet。然后,等待 Applet 運(yùn)行(你將在狀態(tài)欄中看到 Applet 已啟動(dòng)的信息),退出瀏覽器,并打開Javalog.txt 文件。你將會(huì)發(fā)現(xiàn)類似于下列行的信息:
??????? 1000 things constructed
??????? 0 things finalized
正如你能夠看到的那樣,建立了1,000個(gè)對象仍然沒有迫使垃圾回收器開始回收空間,即使在 Applet 退出時(shí)也沒有對象被使用。
現(xiàn)在,刪除在stop() 方法第一行中的注釋符以起用System.gc() 方法。再次編譯并運(yùn)行該 Applet ,等待 Applet 完成運(yùn)行,并退出瀏覽器。當(dāng)你再次打開Javalog.txt 文件,你將看到下列行:
??????? 1000 things constructed
??????? 963 things finalized
這次,垃圾回收器認(rèn)為大多數(shù)對象未被使用,并將它們回收。按順序,當(dāng)垃圾回收器開始釋放這些對象的內(nèi)存時(shí),JVM 調(diào)用它們的finalize() 方法。
繼承finalize()?
順便,如果你在類中定義了finalize() ,它將不會(huì)自動(dòng)調(diào)用基類中的方法。在我們討論了finalize() 與 C++ 的析構(gòu)函數(shù)的不同點(diǎn)后,對這個(gè)結(jié)論不會(huì)驚訝,因?yàn)闉槟硞€(gè)類定制的清除代碼另一個(gè)類不一定會(huì)需要。
如果你決定要通過派生一個(gè)類的finalize() 方法來調(diào)用基類中的finalize() 方法,你可以象其他繼承方法一樣處理。
??????? protected void finalize()
??????? {
??????? ? super.finalize();
??????? ? // other finalization code...
??????? }
除了允許你控制是否執(zhí)行清除操作外,這個(gè)技術(shù)還使你可以控制當(dāng)前類的finalize() 方法何時(shí)執(zhí)行。
結(jié)論
然而有益的是,Java 的自動(dòng)垃圾回收器不會(huì)失去平衡。作為便利的代價(jià),你不得不放棄對系統(tǒng)資源釋放的控制。不象 C++ 中的析構(gòu)函數(shù),Java Applet 不會(huì)自動(dòng)執(zhí)行你的類中的finalize() 方法。事實(shí)上,如果你正在使用 Java 1.0,即使你試圖強(qiáng)制它調(diào)用finalize() 方法,也不能確保將調(diào)用它。
因此,你不應(yīng)當(dāng)依靠finalize() 來執(zhí)行你的 Applet 和應(yīng)用程序的資源清除工作。取而代之,你應(yīng)當(dāng)明確的清除那些資源或創(chuàng)建一個(gè)try...finally 塊(或類似的機(jī)制)來實(shí)現(xiàn)。
finalize方法是與Java編程中的垃圾回收器有關(guān)系。即:當(dāng)一個(gè)對象變成一個(gè)垃圾對象的時(shí)候,如果此對象的內(nèi)存被回收,那么就可以調(diào)用系統(tǒng)中定義的finalize方法來完成
當(dāng)然,Java的內(nèi)存回收可以由JVM來自動(dòng)完成。如果你手動(dòng)使用,則可以使用上面的方法。
舉例說明:
結(jié)果運(yùn)行:
view plain
final
修飾符(關(guān)鍵字)如果一個(gè)類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承。因此一個(gè)類不能既被聲明為 abstract的,又被聲明為final的。將變量或方法聲明為final,可以保證它們在使用中不被改變。被聲明為final的變量必須在聲明時(shí)給定初值,而在以后的引用中只能讀取,不可修改。被聲明為final的方法也同樣只能使用,不能重載。?
?
finally
異常處理時(shí)提供 finally 塊來執(zhí)行任何清除操作。如果拋出一個(gè)異常,那么相匹配的 catch 子句就會(huì)執(zhí)行,然后控制就會(huì)進(jìn)入 finally 塊(如果有的話)。一般異常處理塊需要。
?
finalize
方法名。Java 技術(shù)允許使用 finalize() 方法在垃圾收集器將對象從內(nèi)存中清除出去之前做必要的清理工作。這個(gè)方法是由垃圾收集器在確定這個(gè)對象沒有被引用時(shí)對這個(gè)對象調(diào)用的。它是在 Object 類中定義的,因此所有的類都繼承了它。子類覆蓋 finalize() 方法以整理系統(tǒng)資源或者執(zhí)行其他清理工作。finalize() 方法是在垃圾收集器刪除對象之前對這個(gè)對象調(diào)用的。?
Java中所有類都從Object類中繼承finalize()方法。
當(dāng)垃圾回收器(garbage colector)決定回收某對象時(shí),就會(huì)運(yùn)行該對象的finalize()方法。值得C++程序員注意的是,finalize()方法并不能等同與析構(gòu)函數(shù)。Java中是沒有析構(gòu)函數(shù)的。C++的析構(gòu)函數(shù)是在對象消亡時(shí)運(yùn)行的。由于C++沒有垃圾回收,對象空間手動(dòng)回收,所以一旦對象用不到時(shí),程序員就應(yīng)當(dāng)把它delete()掉。所以析構(gòu)函數(shù)中經(jīng)常做一些文件保存之類的收尾工作。但是在Java中很不幸,如果內(nèi)存總是充足的,那么垃圾回收可能永遠(yuǎn)不會(huì)進(jìn)行,也就是說filalize()可能永遠(yuǎn)不被執(zhí)行,顯然指望它做收尾工作是靠不住的。
那么finalize()究竟是做什么的呢?它最主要的用途是回收特殊渠道申請的內(nèi)存。Java程序有垃圾回收器,所以一般情況下內(nèi)存問題不用程序員操心。但有一種JNI(Java Native Interface)調(diào)用non-Java程序(C或C++),finalize()的工作就是回收這部分的內(nèi)存。僅供學(xué)習(xí)參考,原文出自:http://blog.csdn .NET/carolzhang8406/article/details/6705831
總結(jié)
以上是生活随笔為你收集整理的java finalize方法的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 11:数组作为函数参数,数组做
- 下一篇: Java IO - Reader