每每说到类,不得不介绍的就是类的定义,它是一个抽象的概念,它是一个模板,制造对象的模板
1.定义一个类
class Preson {
// 类的成员变量
}
默认情况下,class关键字没有显式的使用
internal
修饰符来定义类,但是没有必要这样做,默认的修饰符就是internal
除了internal这个权限修饰符以外,还有以下的权限修饰符
2.类的成员
定义完类之后,还需要再类中定义成员,类的成员包括字段、属性、方法和构造函数等等
类的成员也有权限修饰符
2.1 字段
public class Person {
// 姓名,类型位字符串
private string name;
// 年龄,类型为int类型
public int age;
// 性别,类型为bool
protected bool sex;
}
除了以上的修饰符以外,还可以使用关键字 readonly 和 const 来定义字段,若使用 readonly 修饰字段,则该字段为只读的,若使用 const 修饰字段,则该字段是不可变的
public class Person {
private readonly string name;
public const int age = 18;
protected bool sex ;
}
readonly 与 const 的区别
若使用readonly修饰字段,则不需要在定义时初始化,而是可以在构造函数中完成初始化,但是使用const 进行修饰,则需要在定义时初始化
static 修饰
除了 readonly、const 修饰,还可以是 static 修饰,使用 static 修饰,静态字段必须通过类了进行访问,而实例字段通过对象实例来访问
public class Person {
public static string name;
public int age;
}
// 访问方式的不同
new Person().age;
Person.name
2.2 属性
属性是对字段的扩展,是根据OOP思想对字段进行封装的结果,通过这种封装可以防止客户端直接对字段进行篡改
public class Person {
// 私有字段定义
private string name;
public string Name {
get {
return name;
}
set {
// value是隐式参数
name = value;
}
}
}
在上段代码中,我们的get、set访问器是可读可写的,但是get、set构造器也可以设置访问权限
public class Person {
private string name;
private int age;
private bool sex;
public string Name {
get {
return name;
}
// 私有set访问器
private set {
name = value
}
}
public int Age {
// 不包含set访问器,只读属性定义
get {
return age;
}
}
}
和静态字段类似,属性也可以通过static关键字声明为静态属性,静态属性属于类级别,不能通过类的实例进行访问,也不能在静态属性中使用非静态的字段
public class Person {
private static string name;
// 静态属性
public static string Name {
get {
return name;
}
set {
name = value;
}
}
}
2.3 方法
方法就和 Java中的方法类似
注意
:Main方法是每个C#应用程序的入口点,在启动应用程序时,Main由公共语言运行时(CLR)负责调用
public class Person {
// 类定义了一个没有返回值的打印方法
// name是用户传入的参数
public void Print(string name) {
Console.WriteLine("输入的值为:"+name);
}
}
class Program {
static void Main(string[] args) {
Person p = new Person();
p.Print("张三");
}
}
方法重载
前面提到过 C# 的运算符支持重载,同样 C# 的方法也支持重载,方法重载中可以定义多个名称相同但是,方法签名不同的方法
方法签名不同指的是:
- 参数的顺序
- 参数的类型
- 参数的个数
class Program
{
static void Main(string[] args) {
Person p = new Person();
p.Print("张三");
p.Print(18);
p.Print("张三",18);
}
}
public class Person
{
// 打印方法
public void Print(string name) {
Console.WriteLine("输入的值:"+name);
}
// 这种只是返回值与原有的方法不同的,不属于方法重载
// 以下的方法会报错
public int Print(string name) {
Console.WirteLine("输入的值:"+name);
return 1;
}
// 下面的方法为方法重载
public void Print(int age) {
Console.WriteLine("输入的值:"+age);
}
public void Print(string name,int age) {
Console.WirteLine("输入的值为{0},{1}",name,age);
}
}
2.4 构造函数
构造函数主要用于创建类的实例化对象,当调用构造函数创建一个类的时候,构造函数会为对象分配内存空间,初始化成员变量
构造函数分为实例构造函数和静态构造函数
1.实例化构造函数
class Person {
private string name;
// 实例构造函数
public Person() {
name = "Learning Hard";
}
}
实例化构造函数的特点
- 构造函数必须与类同名
- 构造函数没有返回值
- 构造函数可以进行方法重载
- 如果没有显示的定义一个构造函数,C#编译器会自动生成函数体为空的默认无参构造函数
- 可以对实例化构造函数指定访问级别
2.静态构造函数
除了实例化构造函数外,构造函数还包括静态构造函数,静态构造函数,用于初始化静态成员变量(类似于Java中的静态代码块或者静态内部类)在创建一个实例或引用任何静态成员之前,CLR都将自动调用静态构造函数
class Person
{
private static string name;
static Person() {
name = "Learning Hard";
}
public static string Name
{
get { return name; }
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Person.Name);
Console.WriteLine(Person.Name);
Console.Read();
}
}
静态构造函数的注意点
:
- 静态构造函数不能使用任何访问修饰符
- 静态构造函数不能带有任何的参数
- 静态构造函数只会执行一次
- 不能直接调用静态构造函数
- 在程序中,程序员无法控制静态构造函数的执行时机
2.5 析构函数
析构函数用于在类销毁前释放类实例所使用的托管和非托管资源,对于C#应用程序创建的大多数对象,可以依靠.NET Framework的 GC 来隐式地执行内存管理任务
但是如果封装了非托管的资源对象,在应用程序使用完毕这些非托管资源后,垃圾回收器运行对象的析构函数(Finalize方法)来释放这些资源
class Person {
// 析构函数
~Person() {
Console.WriteLine("析构函数被调用了")
}
}
上面的析构函数隐式的调用了基类Object的Finalize方法
protected override void Finalize()
{
try
{
Console.WriteLine("析构函数被调用了");
}
finally
{
// 调用Object的Finalize方法
base.Finalize();
}
}
析构函数的注意点:
- 不能在结构体中定义析构函数,只能对类使用析构函数
- 一个类只能有一个析构函数
- 无法继承或重载析构函数
- 无法显式地调用析构函数,析构函数是由垃圾回收机制自动调用的
- 析构函数既没有修饰符也没有参数
2.6 索引器
当一个类包含数组成员时,索引器的使用将大大简化类对数组成员的访问,索引器的定义类似于属性,也具有get、set访问器
[修饰符] 数据类型 this[索引类型 index]
{
get {
// 返回类中数组某个元素
}
set {
// 对类中数组元素赋值
}
}
class Person {
private int[] intarray = new int[10];
public int this[int index] {
get
{
return intarray[index];
}
set
{
intarray = value;
}
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Perons();
person[0] = 1;
person[1] = 2;
person[2] = 3;
Console.WriteLine(person[0]);
Console.WriteLine(person[1]);
Console.Read()
}
}
类 与 结构体的区别
- 语法上的区别,定义类要使用关键字 class,而定义结构体则使用struct
- 结构体中不可对声明字段进行初始化,但是类可以
- 如果没有为类显示的定义构造函数,C# 编译器会自动生成一个无参数的实例构造函数,而一旦我们为类定义了一个构造函数,C# 就不再会自动生成隐式构造函数,而结构体中,无论是否显式的定义了构造函数,隐式构造函数一直都存在
- 结构体不能显示的定义无参数的构造函数,而类可以显示的定义一个无参的构造函数
- 在结构体的构造函数中,必须要为结构体中的所有字段赋值
- 创建结构体对象,可以不使用
new
关键字,但此时结构体对象的字段值是没有初始值的,但是类必须使用new
关键字来创建对象 - 结构体不能继承结构体或类,但是可以实现接口,而类可以继承类,但是不能继承结构体,它也可以实现接口
- 类是引用类型,而结构体是值类型
- 结构体不能定义析构函数,而类可以由析构函数
- 不能用abstract和sealed关键字修饰结构体