C#详解类型,变量与对象

本节内容:

1.什么是类型(Type

2.类型在C#语言中的作用

3.C#语言的类型系统

4.变量、对象与内存

1.什么是类型(type

类型又名数据类型(Date Type),是数据在内存中存储时的“型号”,小内存容纳大数据会丢失精确度、发生错误大内存存纳小尺寸数据会导致浪费,编程语言的数据类型与数据的数据类型不完全相同

1.2.强类型语言(保证了数据的完整性)(数据受到数据类型的约束严格)与弱类型语言(灵活性与危险性并存)(保证数据的正确性)的比较

*C语言中这里的if里面得的值不为0其他都为真,即使不是bool类型也可通过编译,故为弱类型;

*相对的C#if条件里面必须为bool类型的值,否则编译不过去。

C语言举例-if条件;JavaScript示例:动态类型(极弱类型语言);C#语言对弱类型?/动态类型的模拟

2.类型在C#语言中的作用

2.1.一个C#类型中所包含的信息有:

①存储此类型变量所需的内存空间大小;

②此类型值可表示的最大、最小值范围;

③此类型所包含的成员(如方法、属性、事件等);

④程序运行的时候,此类型的变量在分配内存的什么位置;

Stack简介:比较小,比较快,用于方法(函数)调用,(装多了会爆);

第一种情况为:算法没写好,函数调用过多,栈就爆了;

第二种情况:程序有错误,不小心在栈上分配了太多的内存,栈就爆了;

称为:Stack overflow

Heap简介:即堆,比较大,用于存储对象(实例就放在堆里面),如果忘记回收对象会造成内存浪费,这种浪费学名叫做:内存泄漏。

使用Performance Monitor查看进程的堆(Heap)内存使用量;

关于内存泄漏:C#中存在垃圾回收机制,对象没人用了,有垃圾回收机制自动回收对象的内存。不用像java一样需要手动释放内存,换句话说C#较安全比C++安全得多。

⑤此类型所允许的操作符(运算)如: double result = 3 / 4;结果为0

double result = 3.0 / 4.0;结果为0.75

⑥静态的程序指的是没有在运行的程序。

程序的静态期(编辑器和编译器),动态期(运行期):静态的分析代码,动态的调试程序

可以这么说静态的程序是装在硬盘里的,动态的程序是装在内存里的。

双击一个应用程序(exe)就是一个把存储在硬盘里的静态程序动态加载到内存的过程。

Process(进程)概念介绍:一个程序从硬盘加载到内存开始执行之后,就形成一个进程,换句话说就是这个程序正在运行的实例。进程名与(exe)程序文件名字相同,且每个进程都有一个pidProcess ID

Windows+R键可以打开运行窗口,输入perfmonPerformance Monitor)进入性能监视器,打开性能监视器窗口,该窗口默认监视总的进程,可以点“x”在“+”号中添加具体的进程,监视某一程序的内存占比变化。

3.C#语言的类型系统

C#五大数据类型

类(Class):如WindowsFormConsole

结构体(Structures):如Int32Int64SingleDouble

如:在intf12查看定义:public struct Int32 : IComparable

枚举(Enumerations):如HorizontalAlignmentVisbility

例如:public enum FormWindowState

    {

         //默认大小的窗口。

        Normal = 0,

        //最小化的窗口。

        Minimized = 1,

       //最大化的窗口。

        Maximized = 2,

}

接口(Interfaces

委托(Delegates

C#类型的派生谱系:

Object:引用类型(Reference Type)和值类型(Value Type

引用类型:类、接口、委托

值类型:结构体、枚举

 

最右边的分类上下来看可以分为三组:第一组(与引用类型相关)objectstring(这两个关键词基类(class)为本身)与class interfacedelegate(这三个关键字不是具体的数据类型f12找不到定义的,而是运用这三个关键词去创建他们的数据类型);

第二组(与值类型相关):横线以上:对应的是真正数据类型;横线以下与第一组的横线以下的三个一样,都是去定义各自的类型,没有基类型。

第三组:truefalsebool类型的返回值;void表示不需要返回值,null表示一个引用变量里面的值是空的不属于任何数据类型;vardynamic是用来声明变量的(以后会用到)。

(蓝色的字体表示为现成的数据类型,而且十分常用,甚至被归为关键字了;其次这些数据类型都是基本数据类型(即别的类型都是拿这些数据类型去构成的))

4.变量、对象与内存

*值类型与引用类型的内存存储方式是不同的,不分清将会造成很大错误!

①什么是变量

表面上来看(从C#代码的上下文行文来看),变量的用途是存储数据。

实际上,变量表示了存储位置(例如int x=100;x只是一个标签指向一个地址,数据100就存储在这个地址里面),并且每一个变量都有一个存储类型,以决定什么类型的值能够存入变量。*即变量名称表示(对应着)变量的值在内存中的存储位置

*认识一个事物是由浅入深,由表及里,由现象到本质的过程。

变量一共有7种:

静态变量(static),实例变量(也叫非静态变量)(成员变量、字段),数组元素、值参数、引用参数、输出形参、局部变量。

狭义的变量指的是局部变量,因为其它种类的变量都有自己的约定名称。

  简单地讲,局部变量就是方法体(函数体)里面声明的变量。

变量的声明:

有效的修饰符组合(可无) 类型 变量名 初始化器(可无)如:int x

*总结:变量=以变量名所对应的内存地址为起点,以其数据类型所要求的存储空间为长度的一块内存区域

②值类型的变量:

byte/sbyte/short/ushort为例:

值类型没有实例,所谓“实例”与变量合二为一(因为是结构体struct)。

值类型变量的存储如:byte b;b=100;这两条语句作用为:首先确定byte数据类型需要的存储空间大小,然后去内存中找可以使用的(空的)内存地址,找到内存地址后,就把变量名与该内存地址对应起来,再把100转化为2进制数据写进该地址内存中。

③引用类型的变量与实例:

引用类型变量与实例的关系:引用类型变量里存储的数据是对象(实例)的内存地址解释如下:存储引用类型变量与实例时如:

*创建Student类的引用类型变量:Student stu;创建后便去内存(因为其为局部变量故由栈分配内存)中寻找空闲的内存并分得4个字节的内存空间(凡是引用类型固定分配4字节)

*然后创建Student类的实例:new Student();这个时候要去找空闲的堆内存,找 到之后开始分配内存,这时需要计算需要多大的内存(类中的各种数据占内存的总 和),分完之后还要在该内存块内部进行分组:这块内存是存储哪种数据类型的, 那块属于哪种数据类型...

*最后将其赋值给引用类型变量(把气球给孩子):stu = new Student();此时在内 存中把创建类的实例时分配到的内存地址(内存地址是一个编号不是二进制数)转化为二进制数,并将该二进制数存储到创建Student类引用类型变量stu时分配到的4个字节的内存空间里面(按高低原则)。完成引用类型变量的存储。

这样就可以解释两个不同的引用类型变量来引用同一个实例的情况(两个小朋友分别用自己的两根绳子牵着同一个气球),如下:

{

Student stu1

Student stu2

stu1=new Student();

Stu2=stu1;

}

④变量的默认值(局部变量(main函数外如类里面的变量)一旦创建后在内存块中全部刷为0);注意本地变量不能没有初始值(main函数里的变量),例如:

所谓的本地变量不能没有初始值,指的是不能没有初始值就被其他方法调用,如main函数中的如下语句:

Int x;

Console.WriteLind(x);

由于本地变量x没有初始值就被Console类的WriteLine方法调用了故会报错。

⑤常量(值不可改变的变量)

⑦局部变量是在Stack(栈)上分配内存的(其他一般在堆中分配)

⑥装箱与拆箱(Boxing&Unboxing

补充说明:object是类可以派生出:数值类型和引用类型,但本身是类而类属于引用类型,所以object属于引用类型:内存空间存储被引用对象的地址。其定义为:

public class Object

{

public Object();

}

可见object一般当做引用类型使用。

*装箱:当引用变量引用上的数据的时候就要进行装箱,先把被引用的数据(下面指int x)拷贝一份,封装成一个实例,放在堆上的空闲内存中。

例如 {

int x=100//注意局部变量是在栈上分配内存的

    object obj

    obj=x

}

为了使 obj=x”成立:obj为引用型变量分配到的4个字节内存存的是地址,如果直接把数值型变量x内存里存的数据复制给obj的内存空间,则obj会把内存空间里的数据当做是地址,然后去引用该地址的数据,显然错误。

正确做法为:先在上开辟两块内存空间给int xobj(局部变量)再去中创建int 类型x的内存空间并把内容复制到里面去,然后把该段内存首地址转化为2进制数在复制给在obj的内存,这个过程使“obj=x;语句合法的内存操作”叫做装箱。

*即把栈上的值类型的数据封装成一个object类型的实例放在堆上叫做装箱

*拆箱:例如 {

int x=100

    object obj

    obj=x

Int y=[int]obj;

}

为了使 Int y=[int]obj;(在堆内把obj的数据取出来)”成立:先在栈内存中找到空闲的内存开辟一个4字节(因为yint型)的存储空间存放数值类型变量y,然后将某块内存中存放的obj对象数据的按int32格式把数据(转换)复制到y变量的内存空间中。

*即把堆中obj实例里面的值按要求拆成目标数据类型存储到栈上y(目标数据类型)的内存空间中。

 

*装箱装地址,拆箱按要求拆出数据(如:int y=obj;obj要按int32的格式拆出数据)

*装箱和拆箱会损失程序的性能,慎用。

 

 

原文地址:https://www.cnblogs.com/AhuntSun-blog/p/11736244.html