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

1 什么是类型

1.1 又名数据类型

(1)A data type is a homogeneous collection of values,effectively presented, equipped with a setof operations which manipulate these values.

        性质相同的值的集合有效的表达,配备了一系列专门针对这种类型的值的操作。 也可以说一种数据操作是专门针对某种类型的。

(2)是数据在内存中存储时的“型号”。 (内存:内部存储单元。当今的数据架构为冯诺依曼系统,运算器、控制器——这两个对应CPU,存储器——内存,输入输出系统;老师说如果想深入了解可以看下计算机科学中——《计算机组成原理》,关于硬件方面——单片机)

(就好比车的型号,小型车、中型车等,站3D的空间,数据类型是数据的型号,所占内存的空间。)

硬盘——扩展存储器。程序运行是在内存里运行的,而数据是在硬盘中保存的。关机了,数据存在硬盘里也不会丢,硬盘是用电磁来存储数据的。

软件 —— 操作系统 —— 硬件

(3)小内存容纳大尺寸数据会丢失精确度、发生错误 (发生错误就很麻烦了。)

(4)大内存容纳小尺寸数据会导致浪费 (①内存很少很贵,浪费内存就在浪费配置高内存的费用;②开发的软件内存太大,就会挤占其他程序内存,甚至系统内存,一开你开发的软件就跑的慢,那用户就不喜欢用你的软件,那销量就会大打折扣。)

(5)编程语言的数据类型与数学中的数据类型不完全相同。(同样一种数据类型的名字,在编程和数学中大多数情况下是一样的,有的时候会有比较显著的区别。比如:/ 这个运算符。数学3/4=0.75 ;编程:3/4=0。

1.2 强类型语言与弱类型语言的比较

介绍:当你用一门编程语言写程序的时候,如果数据受到数据类型的约束多,那就是强类型语言,反之是弱类型语言。

1.2.1 C语言示例:if条件

int x;   //int类型是4个字节,每个字节8个bit,一共32位
x = 100; 
long y;  //long类型是8个字节,一共64位
y=100L;
x=100L;  //这里就会报错

运用if语句,条件里只能使用布尔值,不能使用200=x这样的赋值。

C语言就可以这样编译,if的条件里只要不等于0,都是正确的,可以运行大括号里的值

1.2.2 JavaScript示例:动态类型——弱类型语言

给myVar先赋值了100,又赋值了Mr.Okay! 。 然后程序都是可以运行的,这就完全是弱类型语言。

运行:

1.2.3 C#语言对弱类型/动态类型的模仿

运用dynamic这个类型,就获得了类似JavaScript中var的功能。但我们只是模仿,对于初学者,知道有这回事就可以了,暂时还用不着。

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

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

(1)存储此类型变量所需的内存空间大

(2)此类型的值可表示的最大、最小值范围

前缀带s的是有-号的,u的是不带-号的

浮点数:

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

两大用处:静态用处、动态用处。这里指程序的静态与动态

一个程序在没有执行的时候,叫做静态时期

一个程序执行起来了,它就进入了动态时期,也叫作运行时期

遍历所有属性:

运行:

(4)此类型由何基类派生而来

C#有一个技能:反射

示例:

结果:

找寻它的基类:

结果:

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

a.Stack简介 栈

栈的作用,是给方法(函数)调用来用的。

栈比较小,一般只有1-2G

b.Stack overflow——栈溢出

示例:

第二个示例:

stackalloc 是指直接从栈里切一块内存出去,这里用了一个肯定会爆栈的数组。因为这个是不安全的程序,所以要用unsafe,而且还要在VS程序用允许unsaft使用才能运行。C#在这方面保护机制做了很多,就是不想让你直接接触内存。

c.Heap简介 堆

堆是用来存储对象的,也就是实例(就是气球 ),是放在堆里面

堆比较大,一般达到几个G

d.使用Performance Monitor查看进程的堆内存使用量

Process 进程

一个程序从硬盘加载到内存,开始运行之后,就形成一个进程,就是这个程序正在运行的一个实例。

示例:

第一个按钮是增加内存使用,第二个是取消使用,但垃圾收集器还需要过段时间才能响应,通过Performance Monitor,可以查看进程的堆内存使用量,来判断你写的程序吃内存的情况。

Windows+R键 打开软件。

进程在Process里

在这里面找我们软件的名字

然后就可以跑内存数据了:

e.关于内存泄漏——内存的浪费(例如使用完对象忘记回收了)

比较C#和C++

在C++中,如果忘记回收对象了,那就是真正的泄漏了

在C#中,有一个垃圾收集器的机制,不用手动收集,垃圾收集器发现这个对象长期没人使用,就会回收。C#相对会安全一些

(6) 此类型所允许的操作(运算)

例如

3.0/4.0 = 0.75

3/4 = 0

3.C#语言的类型系统

3.1 C#的五大数据类型

3.1.1 类(Classes)

如Window,Form,Console,String

static void Main(string[] args) { Type mytype = typeof(Type); Console.WriteLine(mytype.FullName); //打印mytype所属的类 Console.WriteLine(mytype.IsClass); //打印mytype是不是一个类的结果 }

鼠标移到type,按F12——转到定义。老师说要多看这些

3.1.2 结构体(Structures)

如Int32,Int64,Single,Double

int类型:int类型太常用了,C#就把它吸收为关键字了。

3.1.3 枚举(Enumerations)

如HorizontalAlignment,Visibility

给一个集合,你只能从这个集合中选择一个值

例如form窗体,只能有三种状态:最大化、最小化、正常体

窗体显现:最大化

enum声明是用来定义枚举类型。

声明数据类型的关键字:

class 类

struct 结构体

enum 枚举

3.1.4 接口(Interfaces)

(高级,新手后续接触,先不讲)

3.1.5 委托(Delegates)

(高级,新手后续接触,老师先不讲)

3.2 C#类型的派生谱系

树状的,带有层级结构的。所有类型都以Object为基类型

(1)图中第一列关键字——引用类型相关

object 类

string 类

class 定义自己类的关键字

interface 定义自己类的关键字

delegate 定义自己类的关键字

(2)图中第二列关键字——值类型相关

横线以上蓝色的:真正的数据类型,对应的值类型

横线以下:

struct 用来定义自己的结构体的

enum 用来定义自己的枚举的

(3)图中第三列关键字

true,false :是bool类型的两个值

void:在函数不需要返回值的时候使用

null:引用变量里的值是空的,不引用任何实例

var,dynamic:用来声明变量的

(4)蓝色的表示:

①现成的数据类型,这些数据类型都是常用的,C#吸收为自己的关键字

②基本的数据类型,别的类型都是拿这些构成的。也叫C#语言内件数据类型

4.变量、对象与内存——核心内容

4.1什么是变量

4.1.1 表面上来看,变量的用途是存储数据

        static void Main(string[] args)
        {
            int x; //声明了一个标准整数的类型变量,名字叫做x
            x = 100; //用100这个值赋值给x,把100装进x
        }

4.1.2 变量的概念之一

实际上,变量表示了存储位置,并且每个变量都有一个类型,以决定什么样的值能够存入变量

解释:

变量表示了存储位置:变量名表示(对应着)变量的值在内存中的存储位置。

4.1.3 变量一共有7种

  1. 静态变量: 一般叫静态字段
  2. 实例变量(也叫非静态变量;成员变量,字段): 一般叫字段
  3. 数组元素 :一般叫数组里面的元素
  4. 值参数(函数的参数):一般就叫参数
  5. 引用参数(函数的参数):一般就叫参数
  6. 输出形参(函数的参数):一般就叫参数
  7. 局部变量:一般叫变量

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

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

示例:静态变量、字段

  class Program
    {
        static void Main(string[] args)
        {
            Student.Amount = 1;
            Student stu= new Student();
            stu.Name = "Test";
        }
    }

    class Student
    {
        public static int Amount;   //静态变量
        public int Age;   //实例变量:字段
        public string Name;

    }

示例:数组

   int[] array = new int[100]; //100个4字节小隔间
            array[99]=100;

示例:方法

class Student
{
    public double Add(double a ,double b)   //括号里的是值参数变量
    {
        return a+b;            
    }
}

引用参数变量:(内容较深,后续函数再讲)

class Student
{
    public double Add(ref double a ,double b)   //在值参数变量前添加ref,就变成引用参数变量
    {
        return a+b;            
    }
}

输出参数变量:(内容较深,后续函数再讲)

class Student
{
    public double Add(out double a ,double b)   //在值参数变量前添加out,就变成输出参数变量
    {
        return a+b;            
    }
}

示例:局部变量——在函数体里声明的变量

public static Add(double a,double b)
{
    double result = a+b;      //result就是局部变量
    return result; 
}

4.1.5 变量的声明

int a;    //这就是声明了一个变量
a = 100;
int b;
b =200;
int c =a+b;
Console.WriteLine(c);

重点:有效的修饰符组合(opt——这个指可有可无的) 类型 变量名 初始化器(opt)

变量名必须是个名词

class Student
{
    public static int Amount;  //这里public static 就是有效的修饰符
    public private static int Amount;  //如果加上private,那么就会报错,这两个只能留一个
}

public static

int

Amount

= 100

有效修饰符组合

类型

变量名

初始化器

总结

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

4.2 值类型的变量

结构体类型是一种值类型,所以用结构体来演示值类型变量在内存中是如何存储的

4.2.1 以byte/sbyte/short/ushort为例(这些是结构体)

计算机是以字节存储和读取数据的。计算机为每一个字节都准备唯一编号

内存地址:字节在计算机科学中的编号。

橘黄色为系统程序,其他程序不能用。旁边空白的为自由内存。

(1)byte示例

byte b;
b=100;

按F1,跳转Viewer

大小:8位整数就是1个字节,byte就在空余的内存地方给8个bit。例如下图这里

如果byte b=100; 那么存储就是01100100

(2)sbyte示例

sbyte sb;
sb =100;

用第一位来表示正负,0表示+,1表示-。

100表示:

-100为按位取反在加1

①每一位都取反,0就变为1,1变为0

②这里的1就是最后1位加1,结果为:

(3)ushort

ushort us;
us =1000;

ushort表示没有符号的短整型

存储空间是2个字节16位:

范围:二进制16个1,换成十进制就是65535

us=1000存储情况:7比6高,所以要从高位开始存储(高高低低原则,高的8位对应高的8位,低的8位对应低的8位)

(4)short

short s;
s=-1000;

范围:开始一位做符号位,剩下15位。二进制15个1,换成十进制就是32767

1000:

-1000:按位取反再加一

按位取反:

再加一:

4.2.2 值类型没有实例,所谓的“实例”与变量合而为一

值类型给它赋了一个值,其实就可以理解是给了一个实例,所以说实例和变量合而为一

就像我们从来不这样写:

int x = new int[];
x = 100;

因为只要一写int x; 不写后面new int[]是一回事。

4.3 引用类型的变量与实例

4.1.3 引用类型变量与实例的关系:引用类型变量里存储的数据是对象的内存地址

他们的关系就像小朋友牵着气球一样。

  class Program
    {
        static void Main(string[] args)
        {
            Student stu;
        }
    }

    class Student
    {
        uint ID;
        ushort Score;
       
    }

uint 32位-4个字节

ushort 16位-2个字节

重点:这两个是成员变量,也叫字段!

引用变量:stu

值类型是按实际大小分配内存,而引用类型不是这样。

系统会直接给引用变量分配四个字节。把里面都刷成0

这里是 小朋友

这就表示整个变量没有引用任何实例。

        static void Main(string[] args)
        {
            Student stu;
            stu = new Student(); //这里才创建了实例
            //包含了Student类中的ID和Score
        }

创建了实例后,有了堆内存的地址,把它保存在stu中

class Student:

这里是 气球

前四个给uint,后两个给ushort

然后把内存地址30000001放入之前的四个字节中(也就是stu引用变量)。注意不是上图六个字节。

这里是 小朋友牵气球

也就是说:

引用变量存的是,实例在堆内存放的内存地址。

到这里,一个小朋友真正牵着一个气球了。


这也解释了,可以用两个引用变量来引用同一个实例。

        static void Main(string[] args)
        {
            Student stu;
            stu = new Student(); 
            Student stu2;
            stu2 = stu;
        }

第一个绿块:stu; 第二个绿块:stu2

4.4 局部变量是stack(栈)上分配内存

比如刚才的Student stu。它是在Main这个函数中的,所以是局部变量,在栈上分配内存。

而Student类里两个成员变量,也叫字段。这两个会随着实例,分配到堆内存中。

4.5 变量默认值

一旦变量在内存中分配好了后,就默认给它都刷成0,这就是它的默认值。

但如果使用本地变量,没有赋值,那就不能编译。(C/C++可以)

C#要求本地变量必须要有明确的赋值。

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

常量是不能再被赋值的。而且const这句赋值要一次性写完。

4.6装箱与拆箱(Boxing & Unboxing)※

实际使用越来越少(牵扯到性能的损失),但面试会考(数据类型在内存中是怎样起作用的)。

4.6.1 装箱

示例:

    class Program
    {
        static void Main(string[] args)
        {
            int x = 100;
            object obj = x; //所有类型都是所属object基类型,这里叫做装箱
        }
    }

x变量在内存中如下图:2进制的100

obj的内存如下图:

装箱的过程:obj要装x

①先把x内存拷贝到堆内存位置;

②再把x堆内存地址放到obj的内存里

这一套操作下来,肯定要损失系统性能。

4.6.2 拆箱

用y把x从obj中拆箱

    static void Main(string[] args)
    {
        int x = 100;
        object obj = x; 
        int y =(int)obj;
        Console.WriteLine(y);
    }

y变量:

把obj引用的值复制过来,y空间里存储的也是整数100的2进制值

从堆上往栈里搬东西,也会损失性能的。

4.6.2 拆箱

用y把x从obj中拆箱

  static void Main(string[] args)
    {
        int x = 100;
        object obj = x; 
        int y =(int)obj;
        Console.WriteLine(y);
    }

y变量:

把obj引用的值复制过来,y空间里存储的也是整数100的2进制值

从堆上往栈里搬东西,也会损失性能的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值