老生常谈–什么是装箱什么是拆箱「建议收藏」

老生常谈–什么是装箱什么是拆箱「建议收藏」我们知道.NET具有两个数据类型:值类型和引用类型。因为值类型没有指针引用,不是分配在托管堆中,也不会被GC回收,因此它比引用类型更加高效。但有时我们需要将一种类型的变量转换为另一种类型,这时我们就可以使用装箱/拆箱。一、什么是装箱装箱就是将值类型的数据存储在引用类型的变量中。例如在方法中创建了int类型的变量,需要将这个值类型赋值给一个引用类型的变量,这就意味着对这个值进行了装箱操作,代码如下:voiddemo(){intnum=25;//这是装箱操作objectobjN

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

我们知道.NET具有两个数据类型:值类型和引用类型。因为值类型没有指针引用,不是分配在托管堆中,也不会被GC回收,因此它比引用类型更加高效。但有时我们需要将一种类型的变量转换为另一种类型,这时我们就可以使用装箱/拆箱。

一、什么是装箱

装箱就是将值类型的数据存储在引用类型的变量中。例如在方法中创建了int类型的变量,需要将这个值类型赋值给一个引用类型的变量,这就意味着对这个值进行了装箱操作,代码如下:

void demo()
{ 
   
  int num= 25;
  //这是装箱操作
  object objNum=num;
}

上面的代码就是将值类型分配给object类型变量的过程,这个就是装箱操作。当我们对一个值进行装箱时,CoreCLR会在堆上分配新对象,并将这个值类型的值复制到新分配的对象实例上,然后返回托管堆中新分配对象的引用。

二、什么是拆箱

将装箱反过来操作就是拆箱,也就是将引用类型变量的值转换回栈中值类型的过程。CoreCLR首先会验证接收的数据类型是否等同于被装类型,如果是就把值复制回基于栈存储的变量中。例如下面的代码中,objNum的底层类型是int,就完成了拆箱操作:

void UnBoxDemo()
{ 
   
  int num= 25;
  // 这是装箱操作
  object objNum= num;
  // 这是拆箱操作
  int num2 = (int)objNum;
}

Tip:与普通的类型转换不同,我们必须将其拆箱到一个恰当的数据类型中。如果我们将数据拆箱到不正确的数据类型中,会抛出InvalidCastException异常。因此为了安全起见,如果不能保证Object类型背后的类型,那么应该使用try/catch语句把拆箱操作包起来。

三、IL 代码

当编译器遇到装箱/拆箱语法时,它会生成包含装箱/拆箱操作的IL代码。使用ildasm.exe查看编译的程序集就会看到装箱和拆箱操作对应的box和unbox指令:

.method assembly hidebysig static
    void  '<<Main>$>g__UnBoxDemo|0_0'() cil managed
{ 
   
  .maxstack  1
  .locals init (int32 V_0, object V_1, int32 V_2)
    IL_0000:  nop
    IL_0001:  ldc.i4.s   25
    IL_0003:  stloc.0
    IL_0004:  ldloc.0
    IL_0005:  box        [System.Runtime]System.Int32
    IL_000a:  stloc.1
    IL_000b:  ldloc.1
    IL_000c:  unbox.any  [System.Runtime]System.Int32
    IL_0011:  stloc.2
    IL_0012:  ret
  } // end of method '<Program>$'::'<<Main>$>g__UnBoxDemo|0_0'

上面的IL代码中来看,装箱/拆箱似乎是一个没用的特性。因为我们很少需要在Object变量中存储值类型。但是实际是装箱/解箱过程是有用的,它允许假设一切都可以被当作Object类型来处理,CoreCLR会帮我们处理与内存有关的细节。

四、总结

从程序员角度来看装箱和拆箱是非常方便的,不需要手动去复制和转移内存中的值类型和引用类型的数据。但是装箱/拆箱背后的栈/堆内存转移也会带来性能问题。以下总结了简单的整型数进行装箱和拆箱的步骤:

  1. 在托管堆中分配新对象;
  2. 在栈中的数据值被转移到该托管堆中的对象上;
  3. 当拆箱时,存储在堆中对象上的值被转移回栈中;
  4. 堆上未使用的对象将最终被GC回收。

很多时候装箱和拆箱操作不会在性能方面造成重大影响,但是如果一个类似于ArrayList这样的集合包含成千上万条数据,而程序又会频繁操作这些数据,性能的影响就会很明显的。因此在平时编程时应尽量避免发生装箱/拆箱操作。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/179620.html原文链接:https://javaforall.net

(0)
上一篇 2022年10月21日 上午7:16
下一篇 2022年10月21日 上午7:36


相关推荐

  • ClipCursor与GetClipCursor

    ClipCursor与GetClipCursorClipCursor nbsp 函数功能 该函数把鼠标限制在屏幕上的一个矩形区域内 如果调用 SetCursor 或用鼠标设置的一个随后的鼠标位置在该矩形区域的外面 则系统自动调整该位置以保持鼠标在矩形区域之内 nbsp 函数原型 BOOLClipCurs CONSTRECT lpRect nbsp 参数 nbsp IpRect 指向 RECT 结构的指针 该结构包含限制矩形区

    2026年3月19日
    2
  • xampp环境下drupal安装心得[通俗易懂]

    xampp环境下drupal安装心得[通俗易懂]开始学习drupal,首先在关于drupal的安装上就出现了困难,让自己郁闷了好久,所幸最后安装成功,虽然依然有一些小瑕疵:貌似没有邮件发送功能,但这些应该是之后可以调整的,装了不下30次,最后担心自己电脑问题,还在同学的电脑上试了一下,安装成功的时候自己快泪奔了%>_能够遇到的问题基本都遇到了,甚至有些问题自己遇到了网上都查不到资料,记下来备忘吧。​安

    2022年7月20日
    23
  • loadrunner的分析结果图显示没有适用于当前设置的数据

    loadrunner的分析结果图显示没有适用于当前设置的数据

    2021年7月17日
    76
  • MySQL 字符集 注意事项

    MySQL 字符集 注意事项utf8 unicode ci 与 utf8 general ci 区别 utf8 unicode ci 和 utf8 general ci 对中英文来说没有实质的差别 utf8 general ci 校对速度快 但准确度稍差 utf8 unicode ci 准确度高 但校对速度稍慢 若数据库中有德语 法语或者俄语需求 需使用 utf8 unicode ci 其他情况用 utf8 general ci 即可 如果你想使用 gb2312 编码 那么建议你使用 latin1 作为数据表的默认字符集 这样就能直

    2025年12月12日
    6
  • 上海汉特:金税接口软件的产生背景及功能[通俗易懂]

    上海汉特:金税接口软件的产生背景及功能[通俗易懂]随着互联网的快速发展,在会计电算化及企业信息化的催化之下,国内企业会计人员的工作效率也发生了翻天覆地的变化,早已进入了省时、高效、安全、统一的无缝状态。国内经济结构转型,企业经营效率优先,以及高度竞争造成的高度个性化与迅速改变的客户需求,令企业与顾客、企业与供方的关系变得更加密切和复杂。强化管理,规范业务流程,提高准确度,加快产品销售数据流转,以及为流通领域信息管…

    2022年5月20日
    43
  • pycharm 远程调试图文_pycharm 远程调试

    pycharm 远程调试图文_pycharm 远程调试1 前期准备保证有一台 Linux 我用的是 ubuntuserver 系统自带 python 以及 python3 环境 保证安装 pycharm 的设备可以 ssh 上去 这个就不多说了 推荐采用本机安装虚拟机 不要问为啥不直接使用本机的 python 因为调试时有些包在 window 上确实不好办 还有一点 Linux 上做开发确实爽 2 配置 pycharm2

    2026年3月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号