欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

net学习之类与对象、new关键字、构造函数、常量和只读变量、枚举、结构、垃圾回收、静态成员、静态类等

程序员文章站 2023-03-27 17:12:31
1.类与对象的关系 类是对一类事务的统称,是抽象的,不能拿来直接使用,比如汽车,没有具体指哪一辆汽车 对象是一个具体存在的,看的见,摸得着的,可以拿来直接使用,比如我家的那辆刚...
1.类与对象的关系

类是对一类事务的统称,是抽象的,不能拿来直接使用,比如汽车,没有具体指哪一辆汽车

对象是一个具体存在的,看的见,摸得着的,可以拿来直接使用,比如我家的那辆刚刚买的新汽车,就是具体的对象

对象是根据类这个模板创建出来的,类里面有哪些特性或者功能对象里面也有,多不得,少不得

 

2.new 一个对象做了哪些事情?

Person person = new Person();new是一个运算符

(1)在内存中开辟一块合适大小的空间

(2)在这个空间里创建对象

(3)调用这个对象的构造函数

(4)返回这个空间的引用地址

 

3.访问修饰符

类的访问修饰符只有public和internal,内部类的访问修饰符可以为private

 

4.属性

属性的本质是一个get和一个set方法,而set方法中定义了一个参数名称为value,所以我们可以在set方法中访问value

属性就是对字段的封装

属性本身不存值,值是存在属性封装的对应的字段中

只要类中的字段要被外界访问,就需要把这个字段封装为属性

 

5.构造函数

(1)构造函数访问修饰符一般情况下是public,没有返回值,方法的名称与类名相同

(2)构造函数在创建这个对象的时候被自动调用,程序员无法手动调用

(3)构造函数有什么用?如果我们希望在创建这个类的对象的同时需要执行一些代码,我们就可以将这些代码写到构造函数中

(4)this关键字代表当前对象,当前运行在内存中的那一个对象,this关键字可以调用其他的构造函数

(5)构造函数调用构造函数:

public Dog(int age,string name):this(age)

{

 

}

public Dog(int age)

{

 

}

调用的时候:Dog dog = new Dog(2,"旺财");程序会先调用Dog(int age)构造函数,然后在调用Dog(int age,string name)构造函数

(6)隐式构造函数:如果程序员没有为类手动添加构造函数,C#编译器在编译的时候会自动添加一个无参数的构造函数

如果添加了构造函数,C#编译器在编译的时候则不会添加

 

6.常量和只读变量

(1)const修饰的数据叫做常量,

常量一旦声明常量的值就不能改变,因为C#编译器在编译的时候声明常量的那句代码不见了,在使用常量的地方就用常量的值替换了

比如

const string name = "小明";

Console.WriteLine(name);

编译之后变为

Console.WriteLine("小明");所以不能赋值

 

readonly修饰的变量只读变量

readonly string name = "小明";

public Person()

{

 

}

编译后

readonly string name ;

public Person()

{

this.name = "小明";

}

const和readonly的区别:

const不能修改值,readonly只能在构造函数中修改值

const在编译的时候就要确定值,readonly在运行时要确定值

 

7.枚举

枚举是一个值类型,每一个枚举成员都对应了一个整型的数值,这个数值默认是从0开始递增

枚举和int类型转换:int a = (int)Direction.South; int i = 2; Direction d = (Direction)i;

枚举和string类型转换:string str = "South"; Direction d = (Direction)Enum.Parse(typeof(Direction),str,true); //true表示忽略 

大小写 

枚举值所对应的数值默认是int类型的,可以在枚举的名字后面加一个冒号来指定这个数值的类型,只能是整型的(byte,short。。。)

如:

enum Direction:byte

{

 

}

好处:限定变量的取值范围,在编码过程中不容易出错

 

8.结构struct

(1)结构中可以定义字段、属性、方法、构造函数,也可以通过new关键字来创建对象

(2)无参数的构造函数无论如何C#编译器都会自动生成,所以我们不能显示的声明无参数的构造函数

(3)在构造函数中必须要为结构体的所有的字段赋值

(4)在构造函数中为属性赋值,不认为是对字段赋值,因为属性不一定是去操作字段

(5)结构是一个值类型,在传递结构变量的时候,会将结构对象里面的每一个字段复制一份,然后拷贝到新的对象中

(6)不能定义自动属性,因为自动属性会生成一个字段,而这个字段必须要求在构造函数中,而我们又不知道这个字段

(7)声明结构体对象可以不new关键字,但是这个时候结构体对象的字段没有初始值,因为没有调用构造函数,而构造函数中必须为字段赋 

值,所以通过new关键字创建的结构体对象的字段就有默认值。

(8)当我们要表示一个轻量级的对象的时候,就可以定位结构以提高速度。根据传值的影响来选择,希望传引用就定义为类,希望传拷贝就 

定义为结构

 

9.垃圾回收

托管代码:被CLR管理的代码

非托管代码:不被CLR管理的代码

应用程序域:当。net应用程序在CLR中运行的时候,CLR会创建一个单独的应用程序域,让。net应用程序在应用程序域中运行

分配在栈空间的变量一旦执行完其所在的作用域(即"{ }"中),这个变量就会CLR立即回收

分配在堆里面的对象没有任何对象引用的时候,这个对象就被标记为“垃圾对象”,等待垃圾回收期回收。

GC会定时的清理堆空间中的垃圾对象,GC清理垃圾对象的频率程序员无法决定,由CLR自动控制

当一个对象被标记为“垃圾对象”的时候,这个对象不一定立即被回收

垃圾回收运行机制:

垃圾回收会根据应用程序的运行情况来使用合适的算法,其中一种算法如下:

CLR会预先开辟一块空间,当创建对象的时候会放在第0代的内存中,当第0代的空间满的时候,GC开始回收第0代,不被标记垃圾的对象会移 

动到第1代内存中,然后第0代空间变为空,当再次创建对象的时候会存储在第0代空间,一直这样重复,第1代空间不满的时候不会回收。当 

第1代空间满的时候,会垃圾回收第1代,然后把老的对象移动到第1代,新对象存储在第0代。第1代到第2代是和第0代到第1代一样,当三代 

都满的时候会报异常说内存溢出

 

GC.GetGeneration(p)获取指定对象是属于第几代,总共有3代,从0开始,0,1,2

GC.Collect();立即让垃圾回收器对所有的代进行垃圾回收

GC.Collect(0);表示对第0代回收GC.Collect(1);表示对第0代和第1代回收

 

Person p = new Person();

GC.GetGeneration(p);值为0

GC.Collect();

GC.GetGeneration(p);值为1

GC.Collect();

GC.GetGeneration(p);值为2

GC.Collect();

GC.GetGeneration(p);值为2

10.析构函数

析构函数不能有访问修饰符,不能有参数,所有不能被继承或重载,在对象被垃圾回收器回收的时候,析构函数被GC自动调用,当没有垃圾 

对象的时候不会被调用,

执行一些清理善后的操作

~Person()

{

 

}

11.静态成员

(1)在这个类第一次被加载的时候,这个类下面所有的静态成员会被加载,静态成员是属于类的,实例成员是属于对象的

(2)静态成员只能被创建一次,所以静态成员只有一份,实例成员有多少个对象就创建多少次

(3)静态成员被创建在静态存储区中,一旦创建直到程序退出才会被回收

(4)什么时候定义为静态的?变量需要被共享的时候,方法需要被反复调用的时候

(5)静态方法中不能直接调用实例成员,因为静态方法被调用的时候,对象有可能没有创建

(6)this/base关键字在静态方法中不能使用,因为有可能对象不存在

(7)在实例方法中可以调用静态成员,因为这个时候静态成员肯定存在

静态成员和实例成员区别:

(1)生命周期不同,静态成员在程序退出时才会被回收,实例成员则在该对象被垃圾回收器回收时才会被回收

(2)存储的位置不同,静态成员存储在静态存储区中,实例成员存储在堆的对象里面

 

12.静态类

(1)静态类中只能声明静态成员

(2)静态类中不能有实例构造函数

(3)静态类中不能被实例化,因为没有实例成员,实例化无意义

(4)静态类不能被继承,因为本质是一个抽象的密封类,所以不能被继承也不能被实例化

(5)如果一个类下面的所有成员都需要被共享,那么就可以把这个类定义为静态类

(6)不能声明一个静态类的变量,比如静态类Person p;

静态构造函数:非静态类也可以有静态构造函数

静态类的成员第一次被访问之前就会执行静态构造函数

静态构造函数只被执行一次