[C#学习笔记]你真的理解拆箱装箱吗?
学习一项新知识的时候,最好的方法就是去实践它。
前言
《CLR via C#》这本神书真的是太有意思了!没错我的前言就是这个。
装箱
首先来看下,下面这段代码

可以看到,每次循环迭代都会初始化一个Point的值类型字段,并将该Point存储到ArrayList中。
但是我们肯定有疑问,ArrayList中究竟存储了什么?是Point结构,Point结构的地址,还是其他完全不同的东西?
为了解答这个问题,我们必须研究一下ArrayList的Add方法,了解它的参数被定义成了什么类型。
可以知道,Add的原型如下:
public virtual Int32 Add(Object value);
说明Add获取的是一个Object参数。也就是说,Add获取对托管对上的一个对象的引用(或指针)来作为参数。但是之前的代码传递的是p,也就是一个Point,是一个值类型。
为了使代码能够正确的工作,Point值类型必须转换成真正的、在堆中托管的对象,而且必须获取对该对象的引用。
那么,这个将值类型转换成引用类型的操作,就叫做装箱。
当值类型的实力进行装箱时,发生了以下三件事情:
1、在托管堆中分配内存。分配的内存量是值类型各个字段所需要的内存量,还要加上托管堆所有对象都有的两个额外成员(类型对象指针和同步块索引)所需要的内存量。关于类型对象指针和同步块索引,可以看我的这边博文:https://www.cnblogs.com/knqiufan/p/10475186.html
2、值类型的字段复制到新分配的堆内存。
3、返回对象地址。现在该地址是对象引用;值类型成了引用类型。
C#编译器自动生成堆值类型实力进行装箱所需的IL代码。
所以在运行时,当前存在于Point值类型实力p中的字段复制到新分配的Point对象中。已经装箱的Point对象(现在是引用类型)的地址返回并传给Add方法。Point对象一直存在于堆中,直至被垃圾回收。
(所以之所以说相比于ArrayList,尽量用泛型List<T>,因为泛型集合List<T>允许开发人员在操作值类型的集合时不需要对集合中的项进行装箱或拆箱操作。这一改进,使性能提高了不少,因为托管堆中需要创建的对象减少了,进而减少了应用程序需要执行的垃圾回收的次数。)
拆箱
说完了装箱,现在来说说拆箱。假定我继续执行以下操作:

它获取ArrayList的元素0包含的引用(或指针),试图将其放到Point值类型的实力p2中。
为此,已经装箱的Point对象中的所有字段都必须复制到值类型变量p2中,后者在线程栈上。
CLR分为两步完成复制:
1、获取已经装箱Point对象中的各个Point字段的地址。这个过程就是拆箱。
2、将字段包含的值从堆复制到基于栈的值类型的实例中。
拆箱并不是直接将装箱过程倒过来,拆箱的代价要低的多。拆箱其实就是获取指针的过程,该指针指向包含在一个对象中的原始值类型(数据字段)。
其实指针指向的是已经装箱实例中的未装箱部分。所以和装箱不同,拆箱不要求在内存中复制任何字节。
已经装箱的值类型实例在进行拆箱时,内部发生了下面这些事情:
1、如果包含“对已经装箱值类型实例的引用”的变量为null,则抛出NullReferenceException异常。
2、如果引用的对象不是所需值类型的已装箱实例,抛出InvalidCastException异常。
[C#学习笔记]你真的理解拆箱装箱吗?的更多相关文章
- Java四种引用--《深入理解Java虚拟机》学习笔记及个人理解(四)
Java四种引用--<深入理解Java虚拟机>学习笔记及个人理解(四) 书上P65. StrongReference(强引用) 类似Object obj = new Object() 这类 ...
- Java虚拟机内存溢出异常--《深入理解Java虚拟机》学习笔记及个人理解(三)
Java虚拟机内存溢出异常--<深入理解Java虚拟机>学习笔记及个人理解(三) 书上P39 1. 堆内存溢出 不断地创建对象, 而且保证创建的这些对象不会被回收即可(让GC Root可达 ...
- Java 从Character和char的区别来学习自动拆箱装箱
本文结构 1.Character和char 的区别: 2.自动拆箱装箱 1.Character和char 的区别: Character是类,char基本数据类型. 在java中有三个类负责对字符的操作 ...
- WPF中多线程统计拆箱装箱和泛型的运行效率
WPF中多线程统计拆箱装箱和泛型的执行效率.使用的知识点有泛型.多线程.托付.从样例中能够看到使用泛型的效率至少提升2倍 MainWindow.xaml <Window x:Class=&quo ...
- [ 转载 ]学习笔记-深入剖析Java中的装箱和拆箱
深入剖析Java中的装箱和拆箱 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱 ...
- 【学习笔记】深入理解js原型和闭包(0)——目录
文章转载:https://www.cnblogs.com/wangfupeng1988/p/4001284.html 说明: 本篇文章一共16篇章,外加两篇后补的和一篇自己后来添加的学习笔记,一共19 ...
- 【疯狂Java学习笔记】【理解面向对象】
[学习笔记]1.Java语言是纯粹的面向对象语言,这体现在Java完全支持面向对象的三大基本特征:封装.继承.多态.抽象也是面向对象的重要组成部分,不过它不是面向对象的特征之一,因为所有的编程语言都需 ...
- CSS学习笔记09 简单理解BFC
引子 在讲BFC之前,先来看看一个例子 <!DOCTYPE html> <html lang="en"> <head> <meta cha ...
- Java中的自动拆箱装箱(Autoboxing&Unboxing)
一.基本类型打包器 1.基本类型:long.int.double.float.boolean 2.类类型:Long.Integer.Double.Float.Boolean 区别:基本类型效率更高,类 ...
随机推荐
- SmallLocks
folly/SmallLocks.h This module is currently x64 only. This header defines two very small mutex types ...
- linux-修改pip源
1.进入家目录的隐藏 .pip目录下 cd ~/.pip 2.创建并修改pip.conf [global]timeout = 10 # 超时 index-url = http://mirrors.a ...
- cpu真实核数
判断依据: 1.具有相同core id的cpu是同一个core的超线程. 2.具有相同physical id的cpu是同一颗cpu封装的线程或者cores. 英文版: 1.Physical id an ...
- Java里的堆(heap)栈(stack)和方法区(method)
基础数据类型直接在栈空间分配, 方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收. 引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量 . 方法 ...
- FM模型
[ 闲聊DNN CTR预估模型] http://www.mamicode.com/info-detail-1465813.html http://blog.csdn.net/bitcarmanlee/ ...
- python之time&datetime
[time] secs:统一值,无local.UTC之分. struct_time:有local.UTC之分. time.time():返回secs,secs为统一值,无local&utc之分 ...
- intellij idea15,SVN commit file提示No changes detected
备注:我用的intellij 15,已经配置了SVN.且我的工程是从SVN导出的 遇到的问题:Subversion提交代码时提示No changes detected,当然新文件想要add也是选项 ...
- sql unsigned
1.数字类型无符号化,取0以上的值 学习传送门 http://www.cnblogs.com/blankqdb/archive/2012/11/03/blank_qdb.html
- for 续2
--------siwuxie095 (二)skip=n 忽略(屏蔽.隐藏)文本前 N 行的内容. (N 必须大于 0,不能等于 0) 格式: FOR /F " ...
- ICG游戏:证明,先手不是必胜就是必败。
简介: ICG游戏:Impartial Combinatorial Games,公平的组合游戏. 以下是定义,来自网络,可能不够严谨: 1.两名选手:2.两名选手轮流行动,每一次行动可以在有限合法操作 ...