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

老生常谈–什么是装箱什么是拆箱「建议收藏」我们知道.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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 6.5——ADRC学习

    6.5——ADRC学习深刻理解PID1.    典型的传递函数——一阶惯性环节一个储能元件(如电感,电容)与一个耗能元件(如电阻)的组合,就能构成一阶惯性环节。如一个RC电路特点:当输入量发生突变时,输出量不能突变,只能按照指数规律逐渐变换,这就反应了该环节具有惯性。(也就是说,惯性环节的输出一开始并不与输入同步按比例变化,直到过渡过程结束,y(t)才能与x(t)保持比例。)而惯性环节的时间常数就是惯性的量度。 我们的…

    2022年5月19日
    34
  • TCP的三次握手与四次挥手理解及面试题(很全面)

    TCP的三次握手与四次挥手理解及面试题(很全面)本文经过借鉴书籍资料、他人博客总结出的知识点,欢迎提问序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。确认号ack:占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文…

    2022年5月5日
    34
  • 快手用户群体分析_抖音、快手竞品分析报告

    快手用户群体分析_抖音、快手竞品分析报告一、产品初步体验介绍体验环境:RedmiNote5A体验时间:2018.7体验人:Cinnamon抖音快手抖音的logo以暗黑色为底,一个大大的亮白立体音符占据中央,强调了抖音重点在于结合音乐,给人的第一感觉就是炫酷,符合年轻人的审美。快手的logo以黄色为主,是一个立体的摄像机,体现了快手重点在于记录。应用首页抖音的底部button遵循传统的排版:刷新-附近/推荐(首页)、关注、拍摄、消息和我…

    2022年5月10日
    87
  • 常用API,基本类型包装类,日期类,异常,集合进阶,IO流,多线程

    常用API,基本类型包装类,日期类,异常,集合进阶,IO流,多线程​十九.常用API19.1MathMath包含执行基本数字运算的方法没有构造方法,如何使用类中的成员呢?看类的成员是否都是静态的,如果是,通过类名就可以直接调用公19.1.1Math的常用方法绝对值publicclassMathDemo{publicstaticvoidmain(String[]args){//publicstaticintabs(inta):返回参数的绝对值System.out.println(

    2022年5月16日
    41
  • tomcat宕机解决方法

    tomcat宕机解决方法最近项目出现tomcat宕机的情况,即项目运行一段时间后tomcat就会停止运行,解决方法步骤如下:首先进入linux服务器,使用命令top进行查看,发现tomcat的cpu利用率很高,超过100%接着,使用命令ps-ef|greptomcat,查找到对应的pid接着使用jmap-heappid.发现PermGen的利用率达到了99.99%,所以初步确定了问题是出在永久带内存

    2022年7月26日
    13
  • Python爬虫入门项目

    Python是什么Python是著名的“龟叔”GuidovanRossum在1989年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言。创始人GuidovanRossum是BBC出品英剧MontyPython’sFlyingCircus(中文:蒙提·派森的飞行马戏团)的狂热粉丝,因而将自己创造的这门编程语言命名为Python。人生苦短,我用python,翻译自”L…

    2022年4月9日
    43

发表回复

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

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