前言:在前面的博文中,我介绍了C#中的构造函数,详情戳:C#中的构造函数详解,建议收藏!在本博文接下来的部分,我将对构造函数、析构函数做一系列的补充,可谓是干货满满!话不多说,开始学习吧!
文章目录
一、构造函数
首先,我们要明确C#中构造函数是什么,它能做什么,它的特点又是什么?为此,我专门的写了一篇博文介绍C#中的构造函数。那么接下来的内容,算是对其的一个补充,并给大家介绍一个与它紧密相关的——析构函数。
1、构造函数的概念
构造函数是一个特殊的函数,它是在创建对象时执行的方法,构造函数具有与类相同的名称,它通常用来初始化对象的数据成员。构造函数的特点如下:
- 构造函数没有返回值。
- 构造函数的名称要与本类的名称相同。
2、构造函数的定义
/// <summary>
/// 创建一个人类
/// </summary>
class Person
{
public Person() // 无参数的构造函数
{
Console.WriteLine("我是Person无参的构造函数");
}
public Person(string name) // 有参数的构造函数
{
Console.WriteLine("我是Person有参的构造函数,你可以叫我{0}", name);
}
}
- public:构造函数的修饰符。
- Person:构造函数的名称。
- name:构造函数的参数。
3、默认构造函数与有参构造函数
在定义一个类时,如果没有定义构造函数,编译器则会自动创建一个不带参数的默认构造函数。例如我创建一个Animal类,如下:
/// <summary>
/// 创建一个动物类
/// </summary>
class Animal
{
}
在创建Anima类时,我们可使用如下代码:
Animal animal = new Animal();
如果我们在定义类时,定义了含有参数的构造函数,这时如果还想使用默认构造函数,就必须显式的进行定义,不然就会出错。例如下面这个案例:
class Animal
{
public Animal(string name)
{
Console.WriteLine("我是Animal有参的构造函数,你可以叫我{0}", name);
}
}
public static void Main(string[] args)
{
Animal animal = new Animal();
}
上面这个错误主要是由于程序中已经定义了一个有参的构造函数,这时创建对象,如果想要使用无参构造函数,就必须进行显式定义。
4、静态构造函数
在C#中,可以为类定义静态构造函数,这种构造函数只执行一次。编写静态构造函数的主要原因是:类有一些静态字段或者属性,需要在第一次使用类之前,从外部源中初始化这些静态字段和属性。
定义静态构造函数时,不能设置访问修饰符,因为其他C#代码从来不会调用它,它只在引用类之前执行一次;另外,静态构造函数不能带有任何参数,而且一个类中只能有一个静态构造函数,它只能访问类的静态成员,不能访问实例成员。例如,定义一个静态构造函数,如下:
static Program() // 静态构造函数
{
Console.WriteLine("我是静态构造函数~");
}
在类中,静态构造函数和无参的实例构造函数是可以共存的,因为静态构造函数是在加载类时执行,而实例构造函数是在创建类的对象时执行。
5、静态构造函数和实例构造函数的使用
class Program
{
static Program() // 静态构造函数
{
Console.WriteLine("我是静态构造函数~");
}
public Program() // 实例构造函数
{
Console.WriteLine("我是实例构造函数~");
}
public static void Main(string[] args)
{
Program p1 = new Program(); // 创建类的对象p1
Program p2 = new Program(); // 创建类的对象p2
}
}
从上面这个案例,我们可以看出:静态构造函数只在引用类之前执行了一次,而实例构造函数则每创建一个对象都会执行一次。
二、析构函数
1、析构函数的概念
析构函数与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。
2、析构函数的定义
通过上面的概念,我们已经明确:析构函数主要用来释放对象资源,.NET Framework类库有垃圾回收功能,当某个类的实例被认为是不再有效,并符合析构条件时,.NET Framework类库的垃圾回收功能就会调用该类的析构函数实现垃圾回收。析构函数是以“~”
来命名的,还是通过上面这个案例,我们为其添加析构函数,如下:
~Program() // 析构函数
{
Console.WriteLine("析构函数自动调用了~");
}
注意:严格来说,析构函数是自动调用的,不需要开发人员显示定义。如果需要定义析构函数,一个类中只能定义一个析构函数。
构造函数和析构函数是类中比较特殊的两种成员函数,主要用来对对象进行初始化和释放对象资源。一般来说,对象的生命周期从构造函数开始,以析构函数结束。
3、析构函数的注意项
- 不能在结构中定义析构函数。只能对类使用析构函数。
- 一个类只能有一个析构函数。
- 无法继承或重载析构函数。
- 无法调用析构函数。它们是被自动调用的。
- 析构函数既没有修饰符,也没有参数。
4、析构函数的调用
- 垃圾回收器决定了析构函数的调用,我们无法控制何时调用析构函数。
- 垃圾回收器检查是否存在应用程序不再使用的对象。如果垃圾回收器认为某个对象符合析构,则调用析构函数(如果有)并回收用来存储此对象的内存。
- 程序退出时会调用析构函数。
- 我们可以通过调用Collect强制进行垃圾回收,但是请不要这样做,因为这样做可能导致性能问题。
三、构造函数与析构函数区别
- 构造函数和析构函数是类中比较特殊的两种成员函数。
- 构造函数是在创建对象时,使用给定的值将对象初始化。
- 析构函数用于释放一个对象。在对象删除前,使用析构函数做一些清理工作,它与构造函数的功能正好相反。
- 对象的生命周期从构造函数开始,从析构函数结束。
- 如果一个类含有构造函数,在实例化该类的对象时就会被调用。如果含有析构函数,则会在销毁对象时调用。
- 构造函数的名字与类名相同,析构函数的名字也跟类名相同,不过析构函数要在名字前加一个波浪号
“~”
。 - 一个类中只能有一个析构函数,并且无法调用析构函数,它是被自动调用的。
- 当退出含有该对象的成员时,析构函数会自动释放这个对象所占用的空间,所以说析构函数是GC自动调用的,不是开发人员所控制的。