装箱和拆箱几乎是所有面试题中必考之一,看上去简单,就往往容易被忽视。其实它一点都不简单的,一个简单的问题也可以从多个层次来解读。

常见面试题目:

1.什么是拆箱和装箱?

2.什么是箱子?

3.箱子放在哪里?

4.装箱和拆箱有什么性能影响?

5.如何避免隐身装箱?

6.箱子的基本结构?

7.装箱的过程?

8.拆箱的过程?

9.下面这段代码输出什么?共发生多少次装箱?多少次拆箱?

int i = 5;
object obj = i;
IFormattable ftt = i;
Console.WriteLine(System.Object.ReferenceEquals(i, obj));
Console.WriteLine(System.Object.ReferenceEquals(i, ftt));
Console.WriteLine(System.Object.ReferenceEquals(ftt, obj));
Console.WriteLine(System.Object.ReferenceEquals(i, (int)obj));
Console.WriteLine(System.Object.ReferenceEquals(i, (int)ftt));

深入浅出装箱与拆箱

有拆必有装,有装必有拆。

在上一文中我们提到,所有值类型都是继承自System.ValueType,而System.ValueType又是来自何方呢,不难发现System.ValueType继承自System.Object。因此Object是.NET中的万物之源,几乎所有类型都来自她,这是装箱与拆箱的基础。

特别注意的是,本文与上一文有直接关联,需要先了解上一文中值类型与引用类型的原理,才可以更好理解本文的内容。

基本概念

拆箱与装箱就是值类型与引用类型的转换,她是值类型和引用类型之间的桥梁,他们可以相互转换的一个基本前提就是上面所说的:Object是.NET中的万物之源

先看看一个小小的实例代码:

            int x = 1023;
object o = x; //装箱
int y = (int) o; //拆箱

装箱:值类型转换为引用对象,一般是转换为System.Object类型或值类型实现的接口引用类型;

拆箱:引用类型转换为值类型,注意,这里的引用类型只能是被装箱的引用类型对象;

由于值类型和引用类型在内存分配的不同,从内存执行角度看,拆箱与装箱就势必存在内存的分配与数据的拷贝等操作,这也是装箱与拆箱性能影响的根源。

装箱的过程

int x = 1023;
object o = x; //装箱

装箱就是把值类型转换为引用类型,具体过程:

  • 1.在堆中申请内存,内存大小为值类型的大小,再加上额外固定空间(引用类型的标配:TypeHandle和同步索引块);
  • 2.将值类型的字段值(x=1023)拷贝新分配的内存中;
  • 3.返回新引用对象的地址(给引用变量object o)

如上图所示,装箱后内存有两个对象:一个是值类型变量x,另一个就是新引用对象o。装箱对应的IL指令为box,上面装箱的IL代码如下图:

拆箱的过程

int x = 1023;
object o = x; //装箱
int y = (int) o; //拆箱

明白了装箱,拆箱就是装箱相反的过程,简单的说是把装箱后的引用类型转换为值类型。具体过程:

  • 1.检查实例对象(object o)是否有效,如是否为null,其装箱的类型与拆箱的类型(int)是否一致,如检测不合法,抛出异常;
  • 2.指针返回,就是获取装箱对象(object o)中值类型字段值的地址;
  • 3.字段拷贝,把装箱对象(object o)中值类型字段值拷贝到栈上,意思就是创建一个新的值类型变量来存储拆箱后的值;

如上图所示,拆箱后,得到一个新的值类型变量y,拆箱对应的IL指令为unbox,拆箱的IL代码如下:

装箱与拆箱总结及性能

装的的什么?拆的又是什么?什么是箱子?

通过上面深入了解了装箱与拆箱的原理,不难理解,只有值类型可以装箱,拆的就是装箱后的引用对象,箱子就是一个存放了值类型字段的引用对象实例,箱子存储在托管堆上。只有值类型才有装箱、拆箱两个状态,而引用类型一直都在箱子里

关于性能

之所以关注装箱与拆箱,主要原因就是他们的性能问题,而且在日常编码中,经常有装箱与拆箱的操作,而且这些装箱与拆箱的操作往往是在不经意时发生。一般来说,装箱的性能开销更大,这不难理解,因为引用对象的分配更加复杂,成本也更高,值类型分配在栈上,分配和释放的效率都很高。装箱过程是需要创建一个新的引用类型对象实例,拆箱过程需要创建一个值类型字段,开销更低。

为了尽量避免这种性能损失,尽量使用泛型,在代码编写中也尽量避免隐式装箱。

什么是隐式装箱?如何避免?

就是不经意的代码导致多次重复的装箱操作,看看代码就好理解了

int x = 100;
ArrayList arr = new ArrayList(3);
arr.Add(x);
arr.Add(x);
arr.Add(x);

这段代码共有多少次装箱呢?看看Add方法的定义:

再看看IL代码,可以准确的得到装箱的次数:

显示装箱可以避免隐式装箱,下面修改后的代码就只有一次装箱了。

int x = 100;
ArrayList arr = new ArrayList(3);
object o = x;
arr.Add(o);
arr.Add(o);
arr.Add(o);

题目答案解析:

1.什么是拆箱和装箱?

装箱就是值类型转换为引用类型,拆箱就是引用类型(被装箱的对象)转换为值类型。

2.什么是箱子?

就是引用类型对象。

3.箱子放在哪里?

托管堆上。

4.装箱和拆箱有什么性能影响?

装箱和拆箱都涉及到内存的分配和对象的创建,有较大的性能影响。

5.如何避免隐身装箱?

编码中,多使用泛型、显示装箱。

6.箱子的基本结构?

上面说了,箱子就是一个引用类型对象,因此她的结构,主要包含两部分:

  • 值类型字段值;
  • 引用类型的标准配置,引用对象的额外空间:TypeHandle和同步索引块,关于这两个概念在本系列后面的文章会深入探讨。

7.装箱的过程?

  • 1.在堆中申请内存,内存大小为值类型的大小,再加上额外固定空间(引用类型的标配:TypeHandle和同步索引块);
  • 2.将值类型的字段值(x=1023)拷贝新分配的内存中;
  • 3.返回新引用对象的地址(给引用变量object o)

8.拆箱的过程?

  • 1.检查实例对象(object o)是否有效,如是否为null,其装箱的类型与拆箱的类型(int)是否一致,如检测不合法,抛出异常;
  • 2.指针返回,就是获取装箱对象(object o)中值类型字段值的地址;
  • 3.字段拷贝,把装箱对象(object o)中值类型字段值拷贝到栈上,意思就是创建一个新的值类型变量来存储拆箱后的值;

9.下面这段代码输出什么?共发生多少次装箱?多少次拆箱?

int i = 5;
object obj = i;
IFormattable ftt = i;
Console.WriteLine(System.Object.ReferenceEquals(i, obj));
Console.WriteLine(System.Object.ReferenceEquals(i, ftt));
Console.WriteLine(System.Object.ReferenceEquals(ftt, obj));
Console.WriteLine(System.Object.ReferenceEquals(i, (int)obj));
Console.WriteLine(System.Object.ReferenceEquals(i, (int)ftt));

上面代码输出如下,至于发生多少次装箱多少次拆箱,你猜?

False
False
False
False
False

欢迎添加个人微信号:Like若所思。

欢迎关注我的公众号,不仅为你推荐最新的博文,还有更多惊喜和资源在等着你!一起学习共同进步!

.NET基础知识(02)-拆箱与装箱的更多相关文章

  1. .NET面试题解析(02)-拆箱与装箱

      系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 装箱和拆箱几乎是所有面试题中必考之一,看上去简单,就往往容易被忽视.其实它一点都不简单的,一个简单的问题也 ...

  2. 《Java基础知识》Java包装类,拆箱和装箱

    虽然 Java 语言是典型的面向对象编程语言,但其中的八种基本数据类型并不支持面向对象编程,基本类型的数据不具备“对象”的特性——不携带属性.没有方法可调用. 沿用它们只是为了迎合人类根深蒂固的习惯, ...

  3. JAVA进阶之旅(一)——增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法

    JAVA进阶之旅(一)--增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法 学完我们的java之旅,其实收获还是很多的,但是依然还有很 ...

  4. MongoDB基础知识 02

    MongoDB基础知识 02 6 数据类型 6.1 null : 表示空值或者不存在的字段 {"x":null} 6.2 布尔型 : 布尔类型只有两个值true和false {&q ...

  5. Java知多少(24)包装类、拆箱和装箱详解

    虽然 Java 语言是典型的面向对象编程语言,但其中的八种基本数据类型并不支持面向对象编程,基本类型的数据不具备“对象”的特性——不携带属性.没有方法可调用. 沿用它们只是为了迎合人类根深蒂固的习惯, ...

  6. JAVA中拆箱和装箱

    浅谈JAVA中拆箱与装箱 一.  什么是装箱?什么是拆箱? 在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行: Integer i = new Integer(10) ...

  7. C# 拆箱与装箱及优化

    1.概念 装箱在值类型向引用类型转换时发生,在堆中分配. 拆箱在引用类型向值类型转换时发生. 2.装箱拆箱的过程 //这行语句将整型常量1赋给object类型的变量obj:众所周知常量1是值类型,值类 ...

  8. [Java学习] Java包装类、拆箱和装箱详解

    虽然 Java 语言是典型的面向对象编程语言,但其中的八种基本数据类型并不支持面向对象编程,基本类型的数据不具备“对象”的特性——不携带属性.没有方法可调用. 沿用它们只是为了迎合人类根深蒂固的习惯, ...

  9. Java包装类、拆箱和装箱详解

    转载:https://www.cnblogs.com/ok932343846/p/6749488.html 虽然 Java 语言是典型的面向对象编程语言,但其中的八种基本数据类型并不支持面向对象编程, ...

随机推荐

  1. 向github项目push代码后,Jenkins实现其自动构建

    配置Jenkins(添加Github服务器) 1.进入[系统管理] --> [系统设置] ,找到[Github] 2.添加Github服务器 这里需要github提供一个密钥文本,我们去gith ...

  2. 【More Effective C++ 条款2】最好使用C++转型操作符

    C的转型方式存在以下两个缺点: 1)几乎允许你将任何类型转化为任何类型,不能精确的指明转型意图,这样很不安全 如将一个pointer-to-base-class-object转型为一个pointer- ...

  3. 23 Maven工程module的移除和重新导入

    1.移除module 移除后: 点击右侧的maven projects: 2.重新导入刚才移除的module (1)方法1 (2)方法2 Ctrl+Shift+ALT+S的快捷键 选择modules ...

  4. Web应急:搜索引擎劫持

    当你直接打开网址访问网站,是正常的,可是当你在搜索引擎结果页中打开网站时,会跳转到一些其他网站,比如博彩,虚假广告,淘宝搜索页面等.是的,你可能了遇到搜索引擎劫持. 现象描述 从搜索引擎来的流量自动跳 ...

  5. 【杂文】NOIP2018 蒟蒻自闭记

    [杂文]NOIP2018 蒟蒻自闭记 都 \(9102\) 年了,谁还记得 \(2018\) 年的事啊 \(QAQ\) . 还有两个月就要去参加首届 \(CSP\) 了. 想着如果再不记下去年那些事儿 ...

  6. mini Redis(项目 二)

    一个仿Redis的内存数据库(主要用来做命令解析)服务端,  客户端使用的开源工具 : https://dom4j.github.io/     github:https://github.com/h ...

  7. ASP.NET Core使用MongoDB数据库

    环境:Asp.Net Core Mvc 2.2,MongoDB 4.09 参考文档:http://mongodb.github.io/mongo-csharp-driver/ http://mongo ...

  8. html5新增表单控件和表单属性

    表单验证 Invalid事件 : 验证反馈 input.addEventListener('invalid',fn,false) 阻止默认验证:ev.preventDefault() formnova ...

  9. 数据库系列(五)之 mysql的伸缩性

    这篇文章,主要讲述mysql的伸缩性.在国内mysql一直都是使用得最多的数据库,在国外也排名前三.mysql是一款开源的.性能较高的数据库. 伸缩性是指在软件设计中,软件(数据库.应用程序)通过特定 ...

  10. Java 之 枚举(Enum)

    一.枚举 1.概述 枚举:JDK1.5引入的,类似于穷举,一一罗列出来 Java 枚举:把某个类型的对象,全部列出来 2.应用 什么情况下会用到枚举类型? 当某个类型的对象是固定的,有限的几个,那么就 ...