小知识中一些易混淆概念总结(三)结构,,静态成员,静态类zhiqiang

经历过毁灭,才可能会有重生!

目录:

一,C#中结构

在C#中可以使用struct关键字来定义一个结构,级别与类是一致的,写在命名空间下面。

1)结构中可以定义属性,字段,方法和构造函数。示例代码如下:

①无论如何,C#编译器都会为结构生成无参数的构造函数;

当我们显式的定义无参数的构造函数,编译时会报错,结果如下:

编译器告诉我们,结构不能包含显式的无参数的构造函数

但是这样编写代码时,编译器却不报错,代码如下:

运行结果如下:

虽然结构不能显式的声明无参数的构造函数,但是程序员却可以显式的调用结构的无参数的构造函数,说明C#编译器无论如何都会为结构生成无参数的构造函数。

②结构中的字段不能赋初始值;

③在结构的构造函数中必须要对结构体的每一个字段赋值;

当我们不声明显式的构造函数时,可以不对成员字段赋值,但是一旦声明了构造函数,就要对所有的成员字段赋值

对所有的成员字段赋值,代码如下:

④在构造函数中对属性赋值不认为对字段赋值,属性不一定去操作字段;

所以在构造函数中我们对字段赋初始值的时候,正确的代码应该是

2)结构体的数值类型问题

C#中的结构是值类型,它的对象和成员字段是分配在栈中的,如下图:

那么当我们写了如下的代码,内存中发生了什么呢?

Point p1=p发生了什么呢?情况如下:

声明结构体对象可以不使用“new”关键字如果不使用“new”关键字声明结构体对象,因为没有调用构造函数,这个时候结构体对象是没有值的。而结构的构造函数必须为结构的所有字段赋值,所以通过"new"关键字创建结构体对象的时候,这个对象被构造函数初始化就有默认的初始值了。实例代码如下:

编译的时候会报错:

3)结构体不能使用自动属性

在第一篇文章我写自动属性的时候,反编译源代码,知道自动属性,会生成一个默认字段。而在结构的构造函数中需要对每一个字段赋值,但是编译器不知道这个字段的名字。所以,没有办法使用自动属性。

那么什么时候定义类,什么时候定义结构体呢?

首先我们都知道的是,栈的访问速度相对于堆是比较快的。但是栈的空间相对于堆来说是比较小的。

①当我们要表示一个轻量级的对象,就可以定义结构体,提高访问速度。

②根据传值的影响来选择,当要传递的引用就定义类,当要传递的是“拷贝”就定义结构体。

二,关于GC(.NET的垃圾回收)

1)分配在栈中的空间变量,一旦出了该变量的作用域就会被CLR立即回收;如下代码:

2)分配在堆里面的对象,当没有任何变量的引用时,这个对象就会被标记为垃圾对象,等待垃圾回收器的回收;

GC会定时清理堆空间中的垃圾对象,这个时间频率是程序员无法控制的,是由CLR决定的。所以,当一个对象被标记为垃圾对象的时候,不一定会被立即回收。

3)析构函数

在回收垃圾对象的时候,析构函数被GC自动调用。主要是执行一些清理善后工作。

析构函数没有访问修饰符,不能有你参数,使用“~”来修饰。 如下面的代码示例:

三,静态成员和实例成员的区别:

静态成员是需要通过static关键字来修饰的,而实例成员不用static关键字修饰。他们区别如下代码:

当类第一次被加载的时候(就是该类第一次被加载到内存当中),该类下面的所有静态的成员都会被加载。实例成员有多少对象,就会创建多少对象。

而静态成员只被加载到静态存储区,只被创建一次,且直到程序退出时才会被释放。

看下面的代码:

那么在内存中发生了什么呢?如下图:

由上面显然可知,定义静态的成员是可以影响程序的执行效率的。那么什么时候定义静态的成员变量呢?

①变量需要被共享的时候②方法需要被反复的调用的时候

2)在静态方法中不能直接调用实例成员。

当类第一次被加载的时候,静态成员已经被加载到静态存储区,此时类的对象还有可能能没有创建,所以静态方法中不能调用类成员字段。实例代码如下:

this和base关键字都不能在静态方法中使用。

②可以创建类的对象指明对象的成员在静态方法中操作,代码如下:

③在实例成员中肯定可以调用静态方法,因为这个时候静态成员肯定存在,代码如下:

静态成员和实例成员的对比:

①生命周期不一样

静态成员只有在程序结束时才会释放,而实例成员没有对象引用时就会释放

②内存中存储的位置不一样

静态成员存放在静态存储区,实例成员在托管堆中。

四,静态类

①静态类被static关键字修饰

②静态类中只能生命静态的成员变量,否则会报错(因为访问该实例成员的时候,类的对象可能还没有被创建)

③静态类中不能有实例的构造函数(如果有实例的构造函数,则该静态类能被实例化,都是静态成员,没有实例成员被调用)

④静态类不能被继承,反编译刚才的两个类,结果如下:

会发现静态类的本质是一个抽象密封类,所以不能被继承和实例化。所以,静态类的构造函数,不能有访问修饰符

如果这个类下面的所有成员的都需要被共享,可以把这个类声明为静态类。

且在一般对象中不能声明静态类型的变量(访问该静态变量时,可能该对象还没有被创建)。

3)静态类的构造函数

静态类可以有静态的构造函数(且所有类都可以有静态的构造函数),如下代码:

执行结果如下:

由此我们可以知道,静态的构造函数会先于实例构造函数执行

当我们在Main()函数中添加如下的代码是:

运行结果如下:

说明静态的构造函数只执行了一次。

---------------------------------------------分割线-----------------------------------------------

THE END
0.接线图!显像管管座的各脚功能及显像管管座结构图显像管管座的各脚功能_显像管管座结构图 1、黑白显像管管脚定义(管座图) 黑白显像管脚数分为七脚管和八脚管两种。它们的主要区别是:七脚管的灯丝一般是③、④两脚,而八脚管的灯丝一般是①、⑧两脚。常见管脚连线名称如图1所示。 2、彩色显像管的构造及管脚定义 jvzquC41yy}/gujehctt0lto1cxuklqg1:>03<61fky0496;1462;9:39;9889;0jvsm
1.《华中科技大学学报(社会科学版)》|汪习根方路锦:论中华民族共同四、民族团结中央立法的规范构造 “合乎逻辑性是良法的基本要求”在规范构造上,首先从整体上明确“民族团结促进法”的基本定位,在此基础上合理确定章节布局、制度设计及其规则要素,最终形成“一个层次分明、结构严谨、有序互动、连为一体的法律系统” (一)“民族团结促进法”的基本定位 jvzq<84jwogotrljvu4iw|y0gf{/ew4kphu039:615;187mvo
2.C++学习13类和对象的定义(构造析构拷贝构造)类的定义 类class与结构体struct的区别 通过类创建对象 构造函数——创建对象 析构函数——销毁/撤销对象 析构函数的调用场景 拷贝构造函数 浅拷贝与深拷贝 拷贝构造函数的调用场景 问题回顾 面向对象和面向过程的区别 面向过程:按照事物发展的逻辑顺序一步一步进行下去。例:C语言。 jvzquC41dnuh0lxfp0tfv8QLHl`hrljvkth1jwvkerf1mjvckrt1:7668=85: