C# 笔记-装箱与拆箱
学一星儿
编辑于 2022年12月24日 23:13
收录于文集
共8篇

视频:装箱和拆箱​

1、为什么会有装箱与拆箱(为什么要学装箱与拆箱):

ArrayList 集合在存数据的时候,会把一切对象都隐式转换成 object 类型,这对于引用类型来说没什么,但是对于值类型来说,需要做额外的操作。

我们知道,作为局部变量的值类型会存放在内存栈上,而引用类型存放在内存堆中,当我们要把值类型封装到 object 时,我们需要把值从内存栈转移到内存堆上,这个过程就是装箱,而这个过程的逆过程,我们称之为拆箱。

2、什么是装箱和拆箱):

官方解释:

    装箱是将值类型转换为 object 类型或由此值类型实现的任何接口类型的过程,(公共语言运行库 (CLR) 对值类型进行装箱时)会将值包装在 System.Object 实例中并将其存储在托管堆中。拆箱将从对象中提取值类型。 

    装箱是隐式的;取消装箱是显式的。

    装箱和取消装箱的概念是类型系统 C# 统一视图的基础,其中任一类型的值都被视为一个对象。

简单理解:

    装箱是把值类型转换成引用类型——值类型 --> 引用类型

    拆箱是把引用类型转换成值类型——引用类型 --> 值类型

装箱和拆箱的过程:

    装箱过程:首先需要在堆内存上分配内存空间,然后构造一个新的 Object 对象,再把栈中的值类型数据封装到引用类型中。

    拆箱过程:需要先在栈中分配一个相同值类型的空间,然后把堆内存中的引用类型强制转换成对应的值类型,把该值类型的值保存到栈中。

3、装箱和拆箱的特点:

    装箱是隐式的,拆箱是显示的。

    因为 Object 是一切类型的基类,而装箱是值类型转换为 Object 类型的过程,也就是装箱是子类到父类的一个类型转换,所以装箱是隐式进行的,而拆箱是一个逆过程,从父类转换到子类,需要进行显示的转换(需要对类型强制转换)。

理清两个疑问:

    值类型与引用类型的继承关系:值类型的基类是 System.ValueType,System.ValueType 的基类是 System.Object

    为什么子类到父类是隐式、而父类到子类是显示:因为一个类只能有一个父类,但是可以有很多子类,所以从子类到父类是唯一的,父类到子类不是唯一的,需要显示指定转换的是哪一个子类。

4、缺点(避免装拆箱)?

耗费性能:相对于简单的赋值操作,装拆箱过程需要进行大量的计算,非常耗费性能

  •     装箱:装箱过程需要在堆内存上分配内存空间,然后构造一个新的 Object 对象,该过程需要进行大量计算。

  •     拆箱:拆箱过程需要进行强制转换,强制转换也需要进行大量的计算。

类型不安全:如果拆箱过程强制转换的类型与给定的类型不一致,会抛出 InvalidCastException (无效的强制转换)异常

代码块
text/x-csharp
自动换行
复制代码
int i = 123;
object o = i;
int j = (short)o;
复制成功

5、装箱和拆箱注意事项:

需要尽量避免代码中出现装箱和拆箱的操作

在把值类型装箱之后,拆箱时需要确保接收的值类型与装箱之前的值类型一致,否则会出错