C#核心概念 - 值类型 & 引用类型 & 装箱拆箱

装箱 (boxing) 和拆箱 (unboxing) 是C#语言特有的概念,支撑了C#的类型系统。

装箱和拆箱在C#的值类型和引用类型之间架起一道桥梁,使二者之间能够互相转换。

C#语言中的所有类型都继承自基类System.Object,即使是最基础的类型如:int, byte, short, bool也是如此,即万物皆对象。其他编程语言会在堆 (Heap) 上分配对象的内存,但C#中万物皆对象,我们不会希望把int这样的类型也分配到堆上。

哪些类型在栈上分配内存,哪些类型在堆上分配内存?C#将数据类型分为值类型 (value) 和引用类型 (reference)。

值类型

包括原类型 (Sbyte、Byte、Short、Ushort、Int、Uint、Long、Ulong、Char、Float、Double、Bool、Decimal)、枚举 (enum)、结构体 (struct)。

值类型在栈中分配内存,在申明时初始化为默认值,初始数据不为NULL,值类型会在超出作用范围时自动释放,不触发垃圾回收算法。

值类型变量包含自身数据,对一个值类型变量进行操作时,并不会影响另一个值类型变量的数据。

int a = 0;
int b = a;  // a = 0, b = 0
b = 10; // a = 10, b = 10 
// 虽然b是由a的数据初始化的,但是改变b的值不会影响a的值

引用类型

包括:类、数组、接口、委托、字符串、字典等等

引用类型是在堆中分配内存用来存储数据,并在栈中分配内存来存储这些数据的一个引用(地址)。初始化为NULL,引用类型需要垃圾回收算法来回收不再使用的内存。

引用类型变量不直接存放数据,而是存放指向数据的地址。那么如果有两个引用类型变量存放了指向同一块内存数据的地址,当对一个引用类型变量所指内存区数据做了修改后,另一个变量所指向的内存区数据自然也会发生变化。

class ReferenceClass {
	public int value = 0;
}

class Text {
	public static void main() {
		ReferenceClass a = new ReferenceClass();
		ReferenceClass b = a; // b和a存放相同的地址,指向同一块内存数据
		a.value = 10; // 修改了a所指向的内存区的数据
		// 此时a.value = 10,且b.value也等于10,因为它们指向同一块数据
	}
}

装箱与拆箱

装箱是指将一个值类型变量转化为引用类型变量的过程。

  • 在堆上分配内存,用于存储值类型的数据。
  • 发生一次内存拷贝动作,将当前存储位置的值类型数据拷贝到堆上分配好的内存位置。
  • 返回对堆上的新内存位置的引用。

与之对应的,拆箱是指将一个引用类型变量转化为值类型变量的过程。

  • 检查已装箱的值的类型兼容目标类型。
  • 发生一次内存拷贝动作,将堆中存储的值拷贝到栈上的值类型实例中。
  • 返回这个新的值。
int i = 0;
System.Object obj = i; // 装箱
int j = (int)obj; // 拆箱
String s = i + ", " + (int)obj; // 两次装箱和一次拆箱
// i转化为字符串类型是第一次装箱,obj转化为int类型是一次拆箱,(int)obj转化为字符串类型是第二次装箱

总结

了解装箱拆箱的概念,主要是能够为了能够分辨出代码中隐藏的装箱拆箱环节,为C#性能优化的打好基础。装箱和拆箱都涉及到内存数据的拷贝,不必要的装箱拆箱会降低程序的性能,应当尽可能避免。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值