【.Net基础二】浅谈引用类型、值类型和装箱、拆箱
目前在看CLR via C#,把总结的记下来,索性就把他写成一个系列吧。
1.【.Net基础一】 类型、对象、线程栈、托管堆运行时的相互关系
2.【.Net基础二】浅谈引用类型、值类型和装箱、拆箱
引用类型和值类型
**引用类型:分配在托管堆中。引用类型直接继承自System.Object。引用类型可以被继承。 **
常用的引用类型有:数组、 类、 接口、 委托、 字符串
**值类型:可分配在线程栈和托管堆中。所有值类型都分为结构或枚举。值类型直接继承自System.ValueType。值类型不可以被继承。 **
例如:System.Int32结构、System.Boolean结构、System.Decimal结构、System.Nullable结构、System.DayOfWeek枚举、System.IO.FileAttributes枚举等都是值类型。
枚举属于值类型,枚举继承自System.Enum,但System.Enum由于特殊性,并不属于值类型,System.Enum属于引用类型。System.Enum继承自System.ValueType。System.ValueType和System.Enum一样,都是属于引用类型,只是CLR对继承自System.ValueType和System.Enum做了特殊处理,内存分配使他具有值类型的特性。编译器也做了特殊处理,例如不能直接继承自这些类。
结构可能我们使用的不多,这里我们可以把它当作一个特殊的“类”。详细的可以参照园子里C#之结构
还有要说明的就是int,double等这些关键字是基元类型,编译器负责将基元类型翻译成对应的FCl(Framework Class Library)中的类型。
来看个例子
class SomeReference { public Int32 x;}//应用类型
struct SomeValue { public Int32 x;}//值类型
static void Main(string[] args)
{
/**第一部分**/
SomeReference re1 = new SomeReference();//在堆上分配
SomeValue va1 = new SomeValue();//在栈上分配
re1.x = 5;
va1.x = 5;
Console.WriteLine(re1.x);//输出5
Console.WriteLine(va1.x);//输出5
/**第二部分**/
SomeReference re2 = re1;//只复制引用(指针)
SomeValue va2 = va1;//在栈上分配并复制成员
re1.x = 8;//re1和re2都会更改
va1.x = 9;//va1会更改,va2不会
Console.WriteLine(re1.x);//输出8
Console.WriteLine(re2.x);//输出8
Console.WriteLine(va1.x);//输出9
Console.WriteLine(va2.x);//输出5
}
第一部分执行完(上一节讲到变量是在序幕代码中进行初始化到栈中):

全部执行完:

装箱和拆箱
这里将一个苹果比喻成值类型,见到苹果能知道他就是吃的苹果,苹果有多种品种(结构和枚举)。
把一个纸箱比喻成引用类型,纸箱可以装各种各样的东西(各种类)。
装箱:将值类型转换为一个引用类型
把苹果装进纸箱(在内存中是复制),就是装箱。装箱运输的话,苹果要仔细打包,很小心。
装箱步骤:
- 在托管堆上分配内存,内存大小为值类型所有字段的大小和类型对象指针加上同步块索引的大小。
- 将值类型的所有字段复制到刚分配的内存中。
- 返回刚分配的内存地址
拆箱:将引用类型转换成值类型
拆箱可能就直接用小刀划开胶带,然后看见苹果(这里已经完成了拆箱),接着取出苹果(在内存中是复制)。
拆箱不是直接把装箱过程倒过来,拆箱的代价要比装箱低的多。拆箱其实就是一个获取指针的过程。不要求在内存中复制任何字节。
拆箱步骤:
- 获取引用类型所有字段对应的地址,这里拆箱已经完成了。
- 拆箱操作完成后,会发生一次字段的复制。
来看个例子
static void Main(string[] args)
{
Int32 v = 5;//值类型
Object o = v;//将值类型转换成应用类型,o引用一个复制的v(已装箱);
v = 123; //将未装箱的值修改成123
Console.WriteLine(v + "," + (Int32)o);//显示123,5
//这里发生了几次装箱?可能大家会看成2次。我刚开始也以为是。
Console.ReadLine();
}
这里容易发生错误的地方就是Console.WriteLine()方法。
正确的装箱次数是3次。
1.Object o = v; 将v转换成o。这是一次。
2.(Int32)o 这涉及到一次拆箱,将o转成Int32,然后再装箱成String?(真的是String吗?那第三次装箱又在哪?)
3.让我们通过ildasm.exe打开程序集,查看IL代码(书中解释的比较详细,我只说关键的地方)。

通过box关键字我们就能看到发生了三次装箱,一次拆箱。
多的一次装箱就发生在Contact方法上。这个Contact方法就是为什么多了一次装箱的关键,三个Object参数,所以对o进行拆箱完装箱其实是Int32转成String
多次装箱拆箱会影响程序的性能和内存消耗,这里不明显,如果在循环中就会产生严重的性能问题。
这里我们可以这样调用
Console.WriteLine(v.ToString() + "," + o);//这里同样显示123,5
v.ToString()方法会返回一个String,String对象已经是引用类型,所以直接传递给Contact方法,不需要任何装箱操作。
这里调用的是String.ValueType(引用类型)的ToString()方法,所以不会发生装箱操作。
o已经指向一个Object引用类型,所以直接传递引用地址就可以。同样不需要进行装箱。
基础很重要,只有在切实理解这些概念之后,才能保证自己长期成功。只有深刻理解之后,才能更快、更轻松的构建高效率应用程序。
转载请注明出处:http://www.cnblogs.com/xcong/p/4066195.html
【.Net基础二】浅谈引用类型、值类型和装箱、拆箱的更多相关文章
- NET中的类型和装箱/拆箱原理
谈到装箱拆箱,DebugLZQ相信给位园子里的博友一定可以娓娓道来,大概的意思就是值类型和引用类型的相互转换呗---值类型到引用类型叫装箱,反之则叫拆箱.这当然没有问题,可是你只知道这么多,那么Deb ...
- java基础1.5版后新特性 自动装箱拆箱 Date SimpleDateFormat Calendar.getInstance()获得一个日历对象 抽象不要生成对象 get set add System.arrayCopy()用于集合等的扩容
8种基本数据类型的8种包装类 byte Byte short Short int Integer long Long float Float double Double char Character ...
- js包装类型的装箱拆箱
https://www.jb51.net/article/155820.htm https://juejin.im/post/5cbaf130518825325050fb0a https://juej ...
- c#基础系列1---深入理解值类型和引用类型
"大菜":源于自己刚踏入猿途混沌拾起,自我感觉不是一般的菜,因而得名"大菜",于自身共勉. 不知不觉已经踏入坑已10余年之多,对于c#多多少少有一点自己的认识, ...
- C#基础知识1-深入理解值类型和引用类型
C#值类型和引用类型这个概念在刚学习的时候应该就知道了.但是我们并没有深入的去理解它.越是基础知识其实才是最有用的.对代码的优化,代码质量的提升都有帮助.通过整理本文章,对很多知识也起到了巩固的作用吧 ...
- 【深入理解CLR】2:细谈值类型的装箱和拆箱
装箱 总所周知,值类型是比引用类型更“轻型”的一种类型,因为它们不作为对象在托管堆中分配,不会被垃圾回收,也不通过指针来引用.但在许多情况下,都需要获取对值类型的一个实例的引用.例如,假定要创建一个A ...
- [CLR via C#]5.3 值类型的装箱和拆箱
原文:[CLR via C#]5.3 值类型的装箱和拆箱 在CLR中为了将一个值类型转换成一个引用类型,要使用一个名为装箱的机制. 下面总结了对值类型的一个实例进行装箱操作时内部发生的事: 1)在托管 ...
- Windows Phone 开发起步之旅之二 C#中的值类型和引用类型
今天和大家分享下本人也说不清楚的一个C#基础知识,我说不清楚,所以我才想把它总结一下,以帮助我自己理解这个知识上的盲点,顺便也和同我一样不是很清楚的人一起学习下. 一说起来C#中的数据类型有哪些,大 ...
- C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)
一:值类型和引用类型的含义参考前一篇文章 C#学习笔记(基础知识回顾)之值类型和引用类型 1.1,C#数据类型分为在栈上分配内存的值类型和在托管堆上分配内存的引用类型.如果int只不过是栈上的一个4字 ...
随机推荐
- 使用UE4.16开发Oculus需要Oculus软件版本高于1.11
使用UE4.16开发Oculus,需要Oculus App Version大于1.11
- AssetsManager 在ios更新失败解决方案
AssetsManager在安卓平台使用正常,但是到ios就不行了,最后发现是 cocos2d\cocos\network\CCDownloader-apple.mm中的 - (void)URLSes ...
- px像素单位与IOS像素单位的换算
本文转载至 http://blog.csdn.net/fanyuna/article/details/24032663 30px转成磅为单位=22磅=二号 磅=(像素/96)*72 =(30/96) ...
- SQL Server中的SQL语句优化与效率
很多人不知道SQL语句在SQL SERVER中是如何执行的,他们担心自己所写的SQL语句会被SQL SERVER误解.比如: select * from table1 where name='zhan ...
- LeetCode-Add and Search Word
Design a data structure that supports the following two operations: void addWord(word) bool search(w ...
- chrome/FF 解析遇到 { 行为一致,返回不一致
测试的时候,发现一个问题,FF下: chrome 下: 你会发现,FF 在解析一直到返回的时候,都是把 {x:1} 当做一个语句块去解析的,而 chrome 在返回的时候返回了对象,把 {x:1} 当 ...
- Python全栈day21(作业针对一个文件进行查询修改删除的操作练习)
需求,有一个配置文件test.conf内容如下 backend www1 server 1 server 2 backend www2 server 3 server 4 add [{'backend ...
- CH5103 传纸条【线性dp】
5103 传纸条 0x50「动态规划」例题 描述 给定一个 N*M 的矩阵A,每个格子中有一个整数.现在需要找到两条从左上角 (1,1) 到右下角 (N,M) 的路径,路径上的每一步只能向右或向下走. ...
- 解决:R读取含中文excel文件,read.xlsx乱码问题
1.新建testexcel.xlsx文件 2.创建R文件:test.R # 定义文件变量 excel_path <- "chapter2/testexcel.xlsx" # ...
- Django内置form表单和ajax制作注册页面
settings.py import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_D ...