C# 构造函数和析构函数
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C# 构造函数和析构函数
构造函数和析构函数是类中的两种特殊方法,其作用分别是对类进行实例化和将实例从内存中删除,并执行相应的指令。
构造函数的名称与类的名称相同,析构函数的名称是由“~”和类名组成的。
例如,如果一个类的类名为std(),那么它的构造函数的名称就是std(),析构函数的名称是~std()。
1 构造函数
构造函数是在类的实例执行时初始化的方法。
由于这个特性使得构造函数成为需要执行的所有初始化任务(如设置变量和属性的初始值)的理想位置。
每个类都有自己的构造函数,在访问这个类的时候系统最先执行的就是这个构造函数。
在定义构造函数时,通常需要将类的名称定义为函数名,并且将类的必要字段、必要属性等作为构造函数的参数,同时还需要定义其修饰符等,如下所示。
class ClassName
{
public
ClassName(Arguments)
{
//……
}
}
在上面的代码中,就定义了一个构造函数,其中,关键字ClassName既表示类的名称,也表示构造函数的名称;关键字Arguments则表示构造函数的参数集合。
需要注意的是,构造函数本身是不会返回任何数据的,因此在编写构造函数时,不需要为其设定数据类型。
在对实例的字段和属性等进行读写操作时,需要确保在当前代码块中对类的成员有
访问权限。
例如,在入口函数main()中操作外部类的字段,就需要该字段具有publ
ic的修饰符。
2 析构函数
析构函数是在类的破坏时自动执行的操作。
析构函数在碎片收集时会自动调用。
析构函数的功能与构造函数完全相反,构造函数用于创建类的实例,析构函数
则主要用于将类的实例清除,以回收内存,并执行相关的各种语句,因此析构函数又被称作“逆构造函数”。
析构函数的命名方式是在类名之前添加波浪号“~”,如下所示。
class ClassName
{
~ClassName()
{
//……
}
}
在上面的代码中,关键字ClassName即为类的名称。
析构函数通常没有参数,也没有返回值。
在使用析构函数时,同样不能直接显式调用。
当没有任何代码要使
用户在使用析构方法是应该注意以下几点:
●不能在一个struct中声明一个析构方法,struct是值类型,它驻留在堆栈(Stack)上,
而不是堆(Heap)上,所以不适合进行垃圾回收。
●不能为析构方法声明一个访问修饰符(例如public),这是因为析构方法不能人为调用,
只能由垃圾回收器来调用。
●不能声明带参数的析构方法,而且它不能接受任何参数。
●编译器自动将一个析构方法转换成对Object.Finalize方法的一个覆盖(override)。
3 垃圾回收器原理
垃圾回收器在它自己的线程中运行,而且只有在特定的时候才会执行(通常是在应用程序执行到一个方法结尾的时候)。
当它运行时,应用程序中运行的其他线程将临时挂起。
这是由于垃圾回收器可能需要移动对象并更新对象引用;因为当对象正在使用时是不能进行这些操作。
垃圾回收器清理对象的步骤如下所示:
●构造包含所有可抵达对象的一个map。
为此,它会反复跟随对象中的引用字段。
垃圾
回收器在构造这个map时,确保循环引用不会造成无限递归。
这个map中的任何的对
象都不会被认为是不可抵达的。
●检查是否有任何不可抵达的对象具有一个需要运行的析构方法(运行析构方法的过程
称为Finalization)。
需要Finalization的任何不可抵达的对象都会放到一个特殊的队列
中。
这个队列称为Freachable队列。
●回收剩余的不可抵达的对象(即不需要Finalization的对象)。
为此,它会在Heap中向
下移动可抵达的对象,从而对Heap进行碎片整理,并释放位于Heap顶部的内存。
当
垃圾回收器移动一个不可达对象时,还将更新对该对象的任何引用。
●允许其他线程恢复执行。
●在一个单独的线程中,对需要Finalization的不可抵达的对象执行Finalize操作(此时,
这些对象在Freachable队列中)。
最后要说的是,有时候在析构函数中清理资源是不太适合的,因为有些资源是很宝贵的,使用完之后必须立即释放。
在这种情况下,惟一的选择是人为释放资源。
在C#中Disposal(处置)方法就是对资源进行处置的一个方法。
如果一个类有Disposal方法,就可以显式地调用它,从而控制何时释放资源。