java析構函數
㈠ 誰能講一下java的析構函數
Java沒有析構函數,java是有自動的垃圾回收機制的。這一點不像c++。
其實,若果想在垃圾回收時做一點事情,可以使用finalize()函數,這是在Object類中定義的,只要重載它就可以了。
例如:protected void
finalize()
{
.............................
// add something....................
}
㈡ java語言放棄了c加加語言的資源回收機制對象必須調用析構函
題主是否想詢問「java語言放棄了c加加語言的資源回收機制對象必須調用析構函數」?存在狀態的變化。一旦C++的對象要被回收了,在回收該對象之前對象的析構函數將被調用,然後釋放對象佔用的內存;而java中一旦垃圾回收器准備好釋放對象佔用的存儲空間,將首先調用其finalize()方法, 並且在下一次垃圾回收動作發生時,才會真正的回收對象佔用的內存。可見在java中,調用GC不等於真正地回收內存資源,而且在垃圾回收中對象存在狀態的變化。
㈢ 簡述構造函數和析構函數的作用
構造函數只是起初始化值的作用,但實例化一個對象的時候,可以通過實例去傳遞參數,從主函數傳遞到其他的函數裡面,這樣就使其他的函數裡面有值了。
析構函數與構造函數的作用相反,用於撤銷對象的一些特殊任務處理,可以是釋放對象分配的內存空間。
把類的聲明放在main函數之前,它的作用域是全局的。這樣做可以使main函數更簡練一些。在main函數中定義了兩個對象並且給出了初值,然後輸出兩個學生的數據。
當主函數結束時調用析構函數,輸出stud has been destructe!。值得注意的是,真正實用的析構函數一般是不含有輸出信息的。
(3)java析構函數擴展閱讀:
當定義一個類的時候,通常情況下都會顯示該類的構造函數,並在函數中指定初始化的工作也可省略,不過Java編譯器會提供一個默認的構造函數.此默認構造函數是不帶參數的。而一般的方法不存在這一特點。
構造函數有回滾的效果,構造函數拋出異常時,構造的是一個不完整對象,會回滾,將此不完整對象的成員釋放(c++)。
當一個類只定義了私有的構造函數,將無法通過new關鍵字來創建其對象,當一個類沒有定義任何構造函數,C#編譯器會為其自動生成一個默認的無參的構造函數。
㈣ 為什麼在Java中不使用finalize方法
Java提供finalize()方法,垃圾回收器准備釋放內存的時候,會先調用finalize()。
(1).對象不一定會被回收。
(2).垃圾回收不是析構函數。
(3).垃圾回收只與內存有關。
(4).垃圾回收和finalize()都是靠不住的,只要JVM還沒有快到耗盡內存的地步,它是不會浪費時間進行垃圾回收的。
有時當撤消一個對象時,需要完成一些操作。例如,如果一個對象正在處理的是非Java 資源,如文件句柄或window 字元字體,這時你要確認在一個對象被撤消以前要保證這些資源被釋放。為處理這樣的狀況,Java 提供了被稱為收尾(finalization )的機制。使用該機制你可以定義一些特殊的操作,這些操作在一個對象將要被垃圾回收程序釋放時執行。
要給一個類增加收尾(finalizer ),你只要定義finalize ( ) 方法即可。Java 回收該類的一個對象時,就會調用這個方法。在finalize ( )方法中,你要指定在一個對象被撤消前必須執行的操作。垃圾回收周期性地運行,檢查對象不再被運行狀態引用或間接地通過其他對象引用。就在對象被釋放之前,Java 運行系統調用該對象的finalize( ) 方法。
finalize()方法的通用格式如下:
protected void finalize( )
{
// finalization code here
}
其中,關鍵字protected是防止在該類之外定義的代碼訪問finalize()標識符。該標識符和其他標識符將在第7章中解釋。
理解finalize( ) 正好在垃圾回收以前被調用非常重要。例如當一個對象超出了它的作用域時,finalize( ) 並不被調用。這意味著你不可能知道何時——甚至是否——finalize( ) 被調用。因此,你的程序應該提供其他的方法來釋放由對象使用的系統資源,而不能依靠finalize( ) 來完成程序的正常操作。
注意:如果你熟悉C ,那你知道C 允許你為一個類定義一個撤消函數(destructor ),它在對象正好出作用域之前被調用。Java不支持這個想法也不提供撤消函數。finalize() 方法只和撤消函數的功能接近。當你對Java 有豐富經驗時,你將看到因為Java使用垃圾回收子系統,幾乎沒有必要使用撤消函數。
理解finalize()-析構函數的替代者
by Tim Gooch
在許多方面,Java 類似於 C++。Java 的語法非常類似於 C++,Java 有類、方法和數據成員;Java 的類有構造函數; Java 有異常處理。
但是,如果你使用過 C++ 會發現 Java 也丟掉一些可能是你熟悉的特性。這些特性之一就是析構函數。取代使用析構函數,Java 支持finalize() 方法。
在本文中,我們將描述 finalize() 與 C++ 析構函數的區別。另外,我們將創建一個簡單的 Applet 來演示 finalize() 是如何工作的。
最終的界限
與 Java 不同,C++ 支持局部對象(基於棧)和全局對象(基於堆)。因為這一雙重支持,C++ 也提供了自動構造和析構,這導致了對構造函數和析構函數的調用,(對於堆對象)就是內存的分配和釋放。
在 Java 中,所有對象都駐留在堆內存,因此局部對象就不存在。結果,Java 的設計者覺得不需要析構函數(象 C++ 中所實現的)。
取而代之,Java 定義了一個特殊的方法叫做finalize() ,它提供了 C++ 析構函數的一些功能。但是,finalize() 並不完全與 C++ 的析構函數一樣,並可以假設它會導致一系列的問題。finalize() 方法作用的一個關鍵元素是 Java 的垃圾回收器。
垃圾回收器
在 C/C++、Pascal和其他幾種多種用途的編程語言中,開發者有責任在內存管理上發揮積極的作用。例如,如果你為一個對象或數據結構分配了內存,那麼當你不再使用它時必須釋放掉該內存。
在 Java 中,當你創建一個對象時,Java 虛擬機(JVM)為該對象分配內存、調用構造函數並開始跟蹤你使用的對象。當你停止使用一個對象(就是說,當沒有對該對象有效的引用時),JVM 通過垃圾回收器將該對象標記為釋放狀態。
當垃圾回收器將要釋放一個對象的內存時,它調用該對象的finalize() 方法(如果該對象定義了此方法)。垃圾回收器以獨立的低優先順序的方式運行,只有當其他線程掛起等待該內存釋放的情況出現時,它才開始運行釋放對象的內存。(事實上,你可以調用System.gc() 方法強制垃圾回收器來釋放這些對象的內存。)
在以上的描述中,有一些重要的事情需要注意。首先,只有當垃圾回收器釋放該對象的內存時,才會執行finalize()。如果在 Applet 或應用程序退出之前垃圾回收器沒有釋放內存,垃圾回收器將不會調用finalize()。
其次,除非垃圾回收器認為你的 Applet 或應用程序需要額外的內存,否則它不會試圖釋放不再使用的對象的內存。換句話說,這是完全可能的:一個 Applet 給少量的對象分配內存,沒有造成嚴重的內存需求,於是垃圾回收器沒有釋放這些對象的內存就退出了。
顯然,如果你為某個對象定義了finalize() 方法,JVM 可能不會調用它,因為垃圾回收器不曾釋放過那些對象的內存。調用System.gc() 也不會起作用,因為它僅僅是給 JVM 一個建議而不是命令。
結論
然而有益的是,Java 的自動垃圾回收器不會失去平衡。作為便利的代價,你不得不放棄對系統資源釋放的控制。不象 C++ 中的析構函數,Java Applet 不會自動執行你的類中的finalize() 方法。事實上,如果你正在使用 Java 1.0,即使你試圖強制它調用finalize() 方法,也不能確保將調用它。
因此,你不應當依靠finalize() 來執行你的 Applet 和應用程序的資源清除工作。取而代之,你應當明確的清除那些資源或創建一個try...finally 塊(或類似的機制)來實現。
finalize方法是與Java編程中的垃圾回收器有關系。即:當一個對象變成一個垃圾對象的時候,如果此對象的內存被回收,那麼就可以調用系統中定義的finalize方法來完成
當然,Java的內存回收可以由JVM來自動完成。如果你手動使用,則可以使用上面的方法。
舉例說明:
㈤ java什麼時候該寫.close()釋放資源
雖然Java有自動內存回收機制,但是如果是資料庫連接、網路連接、文件操作等,不close是不會被回收的,屬於不正確的代碼。x0dx0a也就是說,有close方法,必須得自己調用一下才行。x0dx0a垃圾回收機螞清制僅在Java虛擬機所控制的范圍內釋放資源。x0dx0a對於類似於資料庫連接、socket以及文件操作等,x0dx0a如果有close方法,在你完成任務後執行它x0dx0a並且最好在finally塊內做close,因為即使發生了例外,這些代碼也能被調用。x0dx0a對於使用完了的對象來講,Java不螞野推薦使悶物喊用類似於C++的析構函數來釋放內存(C++中new完後得delete,Java中new完,使用後,將其置x0dx0a成null比較好),因為GC會調節最適當的時間來釋放內存,在程序中濫用delete會降低Java程序的性能(但應該不會引發額外的錯誤)。
㈥ java中什麼是析構方法能不能寫個例子
public class Test {
@Override
public void finalize() {
System.out.println("I'm ending.");
}
public static void main(String... args) throws Throwable {
new Test();
System.gc();
}
}
應該能看到輸出的。我滲陵指測試可以。這個finalize()就是Java在徹底叢配刪除一個對象前汪譽執行的方法,跟你說的析構方法應該是同一個意思。
㈦ java 類中的建構函式和解構函式名都是什麼,java需要手動釋放資源嗎
java 類中的建構函式和解構函式名都是什麼,java需要手動釋放資源嗎?
java中建構函式名與類名相同,java沒有解構函式,java不需要手動釋放資源,它是有垃圾回收機制的。
不要隨便地將建構函式和解構函式的定義體放在類宣告中。
inline不inline,並不會影響建構函式的預設語義,不會因為不是inline的,就不執行基類的構造。並且分析在外的建構函式,仍然可能是inline的。如果建構函式過於復雜,那麼就是寫在類定義內,仍然是不會被inline的。
我認為原因是這樣的:C++提倡實現與介面相分離,宣告中,只給出需要的引數,甚至只是引數型別旅扒,而沒有引數名。如果你寫在宣告中,不是要給出函式體,那樣實現程式碼大家都能看到了,也許直接去改寫你的.h,然後再重新編譯,以達到對private成員的直接控制,這樣不利於封裝。C++的設計,使得一般的具體編譯器實現沒鎮豎都能做到,把宣告放在.h中,實現放在.cpp中,編譯生成.obj,把.cpp檔案刪除掉(或者就是不發放給使用的使用者),使用者只要這個.obj和.h,就可以將別人實現的程式碼庫,並到自己的程式中用。如果建構函式是在類定義內直接給出程式碼的,這就等於讓使用者隨便改了。它可能比別的一般函式負面效果還大。
建構函式、解構函式、虛擬函式可否內聯,有何意義
在語法上沒有錯誤首先要掌握一點,建構函式、解構函式、虛擬函式可以宣告為行內函數,這在語法上是正確的。
When the object is referenced via a pointer or a reference, a call to a virtual function cannot be inlined, since the call must be resolved dynamically. Reason: the piler can't know which actual code to call until run-time (i.e., dynamically), since the code may be from a derived class that was created after the caller was piled. Therefore the only time an inlinevirtual call can be inlined is when the piler knows the "exact class" of the object which is the target of the virtual function call. This can happen only when the piler has an actual object rather than a pointer or reference to an object. I.e., either with a local object, a global/static object, or a fully contained object inside a posite.
請問:編譯器自動生成的合成解構函式做釋放資源的工作嗎?謝謝!
不會,如果需要釋放資源就要自己寫解構函式
在建構函式中開啟資料庫連線,JAVA沒有解構函式怎麼自動去關閉
子類的構造方法會預設的呼叫父類的無引數夠造方法,如在student類中,在構造方法publicStudent(Stringname,intage,Stringschool){super();這是預設的語句,不用顯示的呼叫this.name=name;this.age=age;this.school=school;}
java中主函式和建構函式誰先載入
當然是先主函式。
程式的入口就是主函式。
至於建構函式。。只有要用到這個類的時候 。就是new出這個類以後才會載入,
我去。後邊的人為什麼要說建構函式呢。。。主函式可是static的靜態的呀 。。在最剛開始載入的時候就枯大載入了的!
需要一個帶注釋的c#程式其中最好標明建構函式,解構函式,屬性等~~
namespace GXLogic
{
public class GetLogicDisposedList
{
#region 成員變數
public string PeancyTimeL; 違法時間起
public string PeancyTimeH; 違法時間迄
public string DisposeTimeL; 處理時間
public string DisposeTimeH; 處理時間
public string PlateType; 號牌種類
public string PlateNumber; 號牌號碼
public string PeancyAdress; 違法地點
public string Derection; 行駛方向
public string PeancyType; 違法行為
public string DisposedPerson; 處理人(當資料為處理型別時候——處理人)
#endregion
public GetLogicDisposedList()
{
PeancyTimeL = "";
PeancyTimeH = "";
DisposeTimeL = "";
DisposeTimeH = "";
PlateType = "";
PlateNumber = "";
PeancyAdress = "";
Derection = "";
PeancyType = "";
DisposedPerson = "";
}
這就是建構函式,解構函式C#很少用.你想了解這些可以看看C++
編寫類String 的建構函式、解構函式 已知類String 的原型為: class String { public: String(const char
String的解構函式
String::~String(void)
{
delete [] m_data;
由於m_data是內部資料型別,也可以寫成 delete m_data;
}
String的普通建構函式
String::String(const char *str)
{
if(str==NULL)
{
m_data = new char[1]; 若能加 NULL 判斷則更好
*m_data = 『 』;
}
else
{
int length = strlen(str);
m_data = new char[length+1]; 若能加 NULL 判斷則更好
strcpy(m_data, str);
}
}
拷貝建構函式
String::String(const String &other)
{
int length = strlen(other.m_data);
m_data = new char[length+1]; 若能加 NULL 判斷則更好
strcpy(m_data, other.m_data);
}
賦值函式
String & String::operate =(const String &other)
{
檢查自賦值
if(this == &other)
return *this;
釋放原有的記憶體資源
delete [] m_data;
分配新的記憶體資源,並復制內容
int length = strlen(other.m_data);
m_data = new char[length+1]; 若能加 NULL 判斷則更好
strcpy(m_data, other.m_data);
返回本物件的引用
return *this;
}
[轉載]為什麼建構函式不能宣告為虛擬函式,解構函式可以
建構函式不能宣告為虛擬函式,解構函式可以宣告為虛擬函式,而且有時是必須宣告為虛擬函式。
不建議在建構函式和解構函式裡面呼叫虛擬函式。
建構函式不能宣告為虛擬函式的原因是:1構造一個物件的時候,必須知道物件的實際型別,而虛擬函式行為是在執行期間確定實際型別的。而在構造一個物件時,由於物件還未構造成功。編譯器無法知道物件
的實際型別,是該類本身,還是該類的一個派生類,或是更深層次的派生類。無法確定。。。
2 虛擬函式的執行依賴於虛擬函式表。而
虛擬函式表在建構函式中進行初始化工作
,即初始化vptr,讓他指向正確的虛擬函式表。而在構造物件期間,虛擬函式表還沒有被初
始化,將無法進行。
編譯器在呼叫基類的建構函式的時候並不知道你要構造的是一個基類的物件還是一個派生類的物件。
解構函式設為虛擬函式的作用:解釋:在類的繼承中,如果有基類指標指向派生類,那麼用基類指標delete時,如果不定義成虛擬函式,派生類中派生的那部分無法析構。例:#include "stdafx.h"
#include "stdio.h"class A{public:A();virtual~A();};A::A(){}A::~A(){
printf("Delete class APn");}
class B : public A{public:B();~B();};B::B(){ }B::~B(){
printf("Delete class BPn");}
int main(int argc, char* argv[]){
A *b=new B;delete b;return 0;}
輸出結果為:Delete class B
Delete class A
如果把A的virtual去掉:那就變成了Deleteclass A也就是說不會刪除派生類里的剩餘部分內容,也即不呼叫派生類的虛擬函式
因此在類的繼承體系中,基類的解構函式不宣告為虛擬函式容易造成記憶體泄漏。所以如果你設計一定類可能是基類的話,必須要宣告其為虛擬函式。正如Symbian中的CBase一樣。
Note:1.
如果我們定義了一個建構函式,編譯器就不會再為我們生成預設構造函數了。
2. 編譯器生成的解構函式是非虛的,除非是一個子類,其父類有個虛析構,此時的函式虛特性來自父類。
3. 有虛擬函式的類,幾乎可以確定要有個虛解構函式。
4. 如果一個類不可能是基類就不要申明解構函式為虛擬函式,虛擬函式是要耗費空間的。5.
解構函式的異常退出會導致析構不完全,從而有記憶體泄露。最好是提供一個管理類,在管理類中提供一個方法來析構,呼叫者再根據這個方法的結果決定下一步的操作。6.
在建構函式不要呼叫虛擬函式。在基類構造的時候,虛擬函式是非虛,不會走到派生類中,既是採用的靜態系結。顯然的是:當我們構造一個子類的物件時,先呼叫基類的建構函式,構造子類中基類部分,子類還沒有構造,還沒有初始化,如果在基類的構造中呼叫虛擬函式,如果可以的話就是呼叫一個還沒有被初始化的物件,那是很危險的,所以C++中是不可以在構造父類物件部分的時候呼叫子類的虛擬函式實現。但是不是說你不可以那麼寫程式,
你這么寫,編譯器也不會報錯。只是你如果這么寫的話編譯器不會給你呼叫子類的實現,而是還是呼叫基類的實現。7.在解構函式中也不要呼叫虛擬函式。在析構的時候會首先呼叫子類的解構函式,析構掉物件中的子類部分,然後在呼叫基類的解構函式析構基類部分,如果在基類的解構函式裡面呼叫虛擬函式,會導致其呼叫已經析構了的子類物件裡面的函式,這是非常危險的。8.
記得在寫派生類的拷貝函式時,呼叫基類的拷貝函式拷貝基類的部分,不能忘記了。
寫一個復數Complex類,該類有建構函式、解構函式、 、=運算過載函式和列印函式,並在main函式中測試
#include <iostream>
using namespace std;
class Complex{
double real;
double imag;
public:
Complex(double pr=1, double pi=1){
real=pr; imag=pi;
cout <<"構造物件...
";
}
~Complex(){ cout <<"析構物件...
"; }
Complex& operator=(const Complex& c){
if(this==&c)
return *this;
real=c.real;
imag=c.imag;
return *this;
}
void display(){
cout <<real<<(imag>=0 ? "+" : "")<<imag<<"i"<<endl;
}
};
int main(){
Complex c1(3.3,-4.4),c2;
c2=c1;
c1.display();
c2.display();
return 0;
}
㈧ java中怎麼沒有析構函數
java中有析構函數,但我們一般用不到它賀纖散,因豎者為java有自動內存回收機制,無需程序員來釋放,也就不要擔心內存泄露,只不過java中析構函數所採用的方式不是C++中的那樣前加~號,在java中
對象析構時會調用void finalize()方法,因此你如果禪氏確實需要析構的話就可以為你寫的類添加一個void finalize(){}方法,來完成你所需要的工作
㈨ 5. 請講一講java析構函數和虛函數的用法和作用。
java沒有析構函數和虛函數,析構函數和虛函數是c++中的。
不過,java中的抽像方法,就相當於c++中的虛函數