一、构造函数的定义
函数就是方法,方法就是函数,一个意思。
构造函数用来创建对象,并且可以在构造函数中对此对象进行初始化。构造函数具有与类相同的名称,它通常用来初始化对象的数据成员。
C#中构造函是在创建给定类型的对象时执行的类方法。构造函数是一个特殊的方法,无论什么时候,只要使用new运算符实例化对象,并且不为 new 提供任何参数,就会调用默认构造函数。除非类是静态的,否则C#编译器将为无构造函数的类提供一个公共的默认构造函数,以便该类可以实例化。
二、构造函数的分类
构造函数分为:实例构造函数,静态构造函数,私有构造函数。
三、格式
访问修饰符 类名 (参数列表)
{
语句块;
}
创建类的对象是使用“类名 对象名 = new 类名()”的方式来实现的。
public Student()
{
}
四、构造函数的特征
- 构造函数可以有重载!
- 构造函数没有返回值,连void也不能写。
- 构造函数的名称必须跟类名一样。
- 构造函数的访问修饰符一般情况下访问修饰符为public(当然也有private)。
- 构造函数不能直接被调用,必须通过关键字new在创建对象时自动调用。
- 不带参数的构造函数称为“默认构造函数”。无论何时,只要使用new运算符实例化对象,并且不为new提供任何参数,就会调用默认构造函数。(即创建构造方法(函数)后,在类当中会生成一个一默认的无参数的构造函数,但是当你写个新的构造函数之后,不管是有参数的还是无参数的,那个默认的无参数的构造函数都被干掉了)。
- 如果一个类中定义了有参构造函数,实例化时需要调用无参构造函数,这时我们就必须定义一个显式无参数构造函数,否则运行会报错。
五、new关键字
new帮助我们做了3件事:
- 在内存中开辟来一块空间;
- 在开辟都空间内创建对象;
- 调用对象的构造函数进行初始化对象。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _20220802_1
{
class Program
{
static void Main(string[] args)
{
Book x1 = new Book();//调用无参构造函数
int k = 0;
Book x2 = new Book(k);//调用有参构造函数
Console.WriteLine(k);//为什么这里k=0,因为构造函数没有返回值
Console.ReadKey();
}
}
public class Book
{
public Book()//无参构造函数
{
}
public Book(int i)//有参构造函数
{
i = 2 + 4;
}
}
}
六、案例
1、实例化后手动给属性赋值。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
stu.Name = "张三";
stu.Age = 18;
stu.Sex = "男";
stu.Score = 99.5;
Console.WriteLine($"姓名:{stu.Name},年龄{stu.Age},性别:{stu.Sex},成绩{stu.Score}");
Console.ReadLine();
}
}
}
using System.Linq;
using System.Text;
namespace ConsoleApp1
{
class Student
{
public string Name { get; set; }
public int Age { get; set; }
public string Sex { get; set; }
public double Score { get; set; }
}
}
2:实例化时直接把参数放进去自动给属性赋值。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student();//无参构造函数的调用
Student stu = new Student("李四", 16, "男", 99.4);
Console.WriteLine("姓名:{0},年龄{1},性别:{2},成绩{3}", stu.Name, stu.Age, stu.Sex, stu.Score);
Console.ReadLine();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApp2
{
class Student
{
//有参构造函数
public Student(string name, int age, string sex, double score)
{
this.Name = name;
this.Age = age;
this.Sex = sex;
this.Score = score;
}
public int Age { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
public double Score { get; set; }
//无参构造函数
public Student()
{
Console.WriteLine("无参构造函数被调用");
}
}
}
3、实例构造函数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApp10
{
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student();//无参构造函数调用
Student stu2 = new Student(10, "20");
Console.WriteLine($"X={stu1.X}---Y={stu1.Y}");//结果为:X=0---Y=0
Console.WriteLine($"X={stu2.X}---Y={stu2.Y}");//结果为:X=10---Y=20
Console.ReadLine();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApp10
{
class Student
{
public int X { get; set; }
public string Y { get; set; }
//无参构造函数
public Student()
{
this.X = 0;
this.Y = "0";
}
//有两个参数构造函数
public Student(int x, string y)
{
this.X = x;
this.Y = y;
}
}
}
4、构造函数重载
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _2022_07_19
{
class Student
{
public Student(string name, int age, char gender, int id)
{
this.Name = name;
this.Age = age;
this.Gender = gender;
this.Id = id;
}
public string Name;
public int Age;
public char Gender;
public int Id;
public Student(string name, int age, char gender)
{
this.Name = name;
this.Age = age;
this.Gender = gender;
}
public void SayHello1()
{
Console.WriteLine("我叫{0},我今年{1},我是{2}生,我的学号是{3}。",Name,Age,Gender,Id);
}
public void SayHello2()
{
Console.WriteLine("我叫{0},我今年{1},我是{2}生。", Name, Age, Gender);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _2022_07_19
{
class Program
{
static void Main(string[] args)
{
Student s01 = new Student("张三", 17, '男', 1001);
s01.SayHello1();
Student s02 = new Student("李四", 19, '女');
s02.SayHello2();
Console.ReadKey();
}
}
}
5、构造函数与this联合
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _2022_07_19
{
class Program
{
static void Main(string[] args)
{
Student s01 = new Student("张三", 17, '男', 1001);
s01.SayHello1();
Student s02 = new Student(19, '女');
s02.SayHello2();
Console.ReadKey();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _2022_07_19
{
class Student
{
public Student(string name, int age, char gender, int id)
{
this.Name = name;
this.Age = age;
this.Gender = gender;
this.Id = id;
}
public string Name;
public int Age;
public char Gender;
public int Id;
public Student( int age, char gender) :this("",age,gender,0)
{
//this.Name = name;
//this.Age = age;
//this.Gender = gender;
}
public void SayHello1()
{
Console.WriteLine("我叫{0},我今年{1},我是{2}生,我的学号是{3}。",Name,Age,Gender,Id);
}
public void SayHello2()
{
Console.WriteLine("我叫{0},我今年{1},我是{2}生。", Name, Age, Gender);
}
}
}
6、静态构造函数
在C#中,可以为类定义静态构造函数,这种构造函数只执行一次。编写静态构造函数的主要原因是类有一些静态字段或属性,需要在第一次使用类之前,从外部源中初始化这些静态字段或属性。
在定义静态构造函数时,不能设置访问修饰符,因为其他C#代码从来不会调用它,它只在引用类之前执行一次;另外,静态构造函数不能带任何参数,而且一个类中只能有一个静态构造函数,它只能访问静态成员,不能访问实例成员。
在类中,静态构造函数和无参数的实例构造函数是可以共存的,因为静态构造函数是在加载类时执行的,而无参数的实例构造函数是在创建类的对象时执行的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _20220802_2
{
class Program
{
static Program()
{
Console.WriteLine("静态构造函数");
}
private Program()
{
Console.WriteLine("实例构造函数");
}
static void Main(string[] args)
{
Program p1 = new Program();
Program p2 = new Program();
Program p3 = new Program();
Console.ReadLine();
}
}
}
- 静态构造函数不使用访问修饰符或不具有参数。
- 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数以初始化类。
- 不能直接调用静态构造函数。
- 无法控制在程序中执行静态构造函数的时间。
- 静态构造函数的一种典型用法是在类使用日志文件且将构造函数用于将条目写入到此文件中时使用。
- 静态构造函数对于创建非托管代码的包装类也非常有用,这种情况下构造函数可调用 LoadLibrary 方法。
- 如果静态构造函数引发异常,运行时将不会再次调用该函数,并且类型在程序运行所在的应用程序域的生存期内将保持未初始化。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApp2
{
class Program
{
public static int X = 0;//静态变量
//实例构造函数
public Program()
{
X = 1;
}
//静态构造函数
static Program()
{
X = 2;//第二步,执行静态构造函数
}
//第一步,程序入口Main最先执行,然后执行静态变量public static int X = 0
static void Main(string[] args)
{
Console.WriteLine(X);//结果为2
Program dd = new Program();//第三步,执行构造函数
Console.WriteLine(X);//结果为1
Console.ReadLine();
}
}
}
调用类的静态函数时的执行顺序:
- 静态变量==>静态构造函数==>实例构造函数
- 静态变量==>静态构造函数==>静态函数
那么调用类的实例函数时的执行顺序则是:
- 非静态变量==>实例构造函数==>实例函数
7、私有构造函数
私有构造函数是一种特殊的实例构造函数。 它通常只在包含静态成员的类中。 如果类具有一个或多个私有构造函数而没有公共构造函数,则在其他类(除嵌套类外)中无法进行实例化。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApp2
{
class Program
{
int i = 0;
private Program()
{
i = 9;
}
static void Main(string[] args)
{
Program ss = new Program();
Console.WriteLine($"i={ss.i}");//运行结果:i=9
Console.ReadLine();
}
}
class person
{
//Program ddd = new Program();//注释打开会报错,错误信息:不可访问,因为它受保护级别限制。因为私有构造函数无法在类的外面实例化。
}
}