C#阶段性复习--第二章

2.1 数据类型

C#的数据类型主要分为两种 值类型和引用类型

值类型变量 本身包含其数据 ,而引用类型变量包含的是 指向包含数据的内存块的引用或称为句柄

其本质区别是:值类型直接存储其值,而引用类型存储对值得引用

值类型数据存储在栈中,而引用类型存储在堆中

堆和栈得主要区别是:

栈在编译时就分配好空间,在代码中有栈的明确定义

堆是在程序运行中动态分配的内存空间,可以根据程序的运行情况,动态分配内存大小,这个内存空间包含的是对另一个内存位置(地址)的引用,即存放实际引用对象值得地方。

下面对不同数据类型的特性进行一个简单的整理:

一、值类型

1. 整数类型

可以存储整数值,分为有符号 (singal) ,无符号 (unsingal) 类型,没啥特殊性质。

2.实数类型

根据实数的精度、范围等要求,C#为实数定义了浮点类型 (float、double)decimal 类型。

若无精度要求,尝试用 float 来声明实数类型变量。

Decimal 类型是一种专门用于财务计算的类型。 如果要将数值以 decimal 类型来处理,就应该用 M(或 m )将其强制指定为 decimal 类型。 例如:decimal num = 123.567M

3.布尔类型

布尔类型数据用于逻辑运算,表示真或假的逻辑结果,占一个字节。C# 语言预定了两个常量标识符 truefalse ,分别表示真和假。

**注意!**在 C# 中,布尔值与整数类型截然不同,布尔型不能与整数类型相互转换,因此,布尔型变量不能用整数来赋值。

4.字符类型

有一类特殊字符,用反斜杠 \ 引导,称为转义字符,用于表示一些无法直接表示的字符。除此之外,Unicode转义序列可用 \u 后跟四位十六进制字符(必须指定全部四位十六进制值)表示,或 \x 后跟差不多四位十六进制字符表示(可以省略前导零)。

例如: \006A 是一个有效的转义序列,而 \u06A\u6A 是无效的。而 \x006A\x06A\x6A 是有效的,并且对应于同一个字符。

5.枚举类型

枚举元素的默认基础类型为 int 枚举类型是一种独特的值类型。它用于声明一组命名的符号常量

举个例子。

1
2
3
4
5
6
7
8
9
10
11
enum orientation: byte
{
north,
south,
east,
west
}

/* 在定义之后,需要声明这个新类型的变量 */

orientation myOri = orientation.north;

从枚举类型到整型的转换需要 显式转换 来完成。

例如 int x = (int) orientation.north;

在有限组数的描述中,使用枚举类型比使用无符号的整数类型更加直观、易读。

6. 结构体类型

在 C# 中,结构体是一种 用户自定义的值类型数据结构 。结构体可以用于存储一组相关的数据,这些数据可能具有不同的类型,类似于类。但与类不同的是,结构体是值类型而类是引用类型。这意味着结构体的实例在上分配内存,而类的实例则在上分配内存。

结构体通常用于**存储轻量级的数据,且不能继承特性。**由于结构体是值类型,对结构体变量的赋值和传递会进行值复制,这可以避免意外的副作用。

二、引用类型

引用类型是 C# 应用程序中的主要对象数据类型。而在应用程序执行的过程中,预定义的对象类型以 new 创建对象实例,并且存储在中,而引用该实例的变量存储在中。

引用类型具有如下特征:
①引用类型的引用变量存储在栈中,被赋值前的值是 null 。实例必须 在托管堆中为引用类型实例分配内存

②使用 new关键字 创建引用类型变量的引用实例( 在托管堆中为引用类型实例分配内存、实例成员初始化等 );

③引用类型与值类型的存储方式

引用类型:引用类型存储在堆中。类型实例化的时候,会在堆中开辟一部分空间存储类的实例。类对象的引用还是存储在栈中。

值类型:值类型总是分配在它声明的地方,作为局部变量时,存储在栈上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Product {
public string Name;
public int Price;
}

void Example() {
// 1. 创建引用变量(此时未关联任何对象)
Product phone; // phone = null

// 2. 创建对象并让引用变量指向它
phone = new Product();
phone.Name = "iPhone";
phone.Price = 9999;

// 3. 复制引用变量(指向同一个对象)
Product anotherPhone = phone;
anotherPhone.Price = 8999; // 修改的是同一个对象!

// 4. 断开引用
phone = null; // 对象仍在堆中,直到 GC 回收
}
  1. 对象(Object)
    • 实际的数据实体,存储在堆内存
    • 包含具体的成员数据(字段、属性等)
    • 比如:new Product() 会在堆中创建一个 Product 对象
  2. 引用变量(Reference Variable)
    • 指向对象的“遥控器”,存储在栈内存
    • 只保存对象在堆中的内存地址(类似门牌号)
    • 比如:Product phone; 中的 phone 变量

关系示意图

复制

1
2
3
4
5
6
7
┌─────────────┐        ┌───────────────┐
│ 栈 Stack │ │ 堆 Heap │
├─────────────┤ ├───────────────┤
│ phone ▢─────┼───────▶│ Product对象 │
│ │ │ - Name = "iPhone"
└─────────────┘ │ - Price = 9999
└───────────────┘

在 C# 里面其实叫托管堆,托管堆不同于堆,它是由 ***CLR(公共语言运行库)***管理,当堆中满了之后,会自动清理堆中的垃圾。所以,作为 .net 开发,我们不需要关心内存释放的问题。

2.1 字符串类型

字符串类型是引用类型,不过是特殊的引用类型。当把一个字符串变量赋给另一个字符串变量时,会发生对内存中同一个字符串的两个引用

1
2
3
4
5
6
7
string str1 = "Big Head Fish";
string str2 = str1;
str2 = "Small Head Fish";

Console.WriteLine(str1);

// 输出的仍然是“中南大学”

常量字符串的值用一对双撇号表示,字符串中也可以包含转义符,由于转义符用 \ 开头,因此表示文件路径是,要采用来纳许两个斜杠。例如:

1
string FileName = "C:\\Big\\Head\\Fish.exe"

C# 语言还提供了另外一种替代方式,就是在字符串常量的前面加上 @,在这个字符后的所有字符都会保持原来的含义,而不会解释为转义符。例如:

1
string FileName = @"C:\Big\Head\Fish.exe"

2.2 数组类型

数组就是 有序的、同一类型数据的集合 。数组实质上是包含多个变量的数据结构,其中每一个变量叫做数组的 元素 ,全部元素的数据类型相同。

说明:

① 数据类型可以是 C# 中任意的数据类型,数组名为一个合法的标识符;[]指名该标识符是一个数组类型变量。

② C# 语言中,数组的声明并不为数组元素分配内存,因此,[] 中不能给定数组中元素的个数。

③ 数组必须在访问前进行初始化。在定义完数组后,必须通过运算符 new 为它分配内存,才能对数组元素进行访问。

2.3 通用类型 object

**在 C# 中,object 是所有数据类型的基类型。它是一种通用类型,可以用来表示任何其他类型的值。**在 C# 中,所有的数据类型都直接或间接地继承自 object 类。因此, obeject 是 .NET  框架中的基本类型。

 由于所有数据类型都可以隐式的转换为 object 类型,因此可以使用 object 类型来存储各种类型的数据。 

 在使用 object 类型时,常见的操作是将特定类型的数据 装箱 到 object 类型中,以及从 object 类型中 拆箱 为特定类型。 装箱是将装箱是将值类型(如 int、float、struct等)转换为通用类型(object),而拆箱是将之前装箱的对象转换回原始的值类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
基本值类型的装箱与拆箱
*/
using System;

namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
int num = 42;
object boxedNum = num; // 装箱操作:将值类型int转换为object类型
Console.WriteLine("boxedNum: {0}", boxedNum);

int unboxedNum = (int)boxedNum; // 拆箱操作
Console.WriteLine("unboxedNum: {0}", unboxedNum);

Console.ReadKey();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
结构体的装箱与拆箱
*/
using System;

namespace ConsoleApplication2
{
// 定义一个结构体Point
struct Point
{
public int X;
public int Y;
}

class Program
{
static void Main(string[] args)
{
Point p = new Point();
p.X = 10;
p.Y = 20;

object boxedPoint = p; // 装箱操作:值类型→引用类型
Point unboxedPoint = (Point)boxedPoint; // 拆箱操作:必须精确匹配类型

Console.WriteLine("X: {0}, Y: {1}", unboxedPoint.X, unboxedPoint.Y); // 输出: X:10, Y:20
Console.ReadKey();
}
}
}

注意:

  1. 类型必须严格匹配

  2. 装箱会创建值得副本,修改原始值类型不会影响装箱后的对象

    1
    2
    3
    4
    int a = 5;
    object boxedA= a;
    a=10;
    Console.WriteLine(int)boxedA);//输出:5(未被修改)
  3. 由于 装箱和拆箱操作的性能开销比较大,可能会导致性能问题。

3.var类型

在 C# 中,var 关键字用于声明隐式类型的局部变量。它允许你在不显式指定数据类型的情况下声明变量。相反,数据类型是由编译器根据变量在初始化时赋的值来确定的。

三、常量与变量

1. 常量

(1)整型常量

​ 具体如下

		1. 二进制:由数字 0 和 1 组成的数字序列。
		2. 八进制: 以数字 0 开头,且其后是由数字 0~7 整数组成的数字序列。
		3. 十进制
		4. 十六进制:以 0x 或者 0x 开头并且后跟 0~9, A~F 组成的数字序列。

(2)浮点数常量

  1. 单精度:通常用 F 或 f 结尾。
  2. 双精度:通常用 D 或 d 结尾。

(3)字符常量 用单引号引起来。

(4)字符串常量

(5)布尔常量

(6)null常量

(7)符号常量

2. 变量

变量具有四个属性:名字、类型、变量值和占用的内存地址。


C#阶段性复习--第二章
https://leoeightxuan.github.io/2025/03/26/C-阶段性复习-第二章/
作者
Leoeight
发布于
2025年3月26日
许可协议