【.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字 ...
随机推荐
- C语言条件运算符
如果希望获得两个数中最大的一个,可以使用 if 语句,例如: if(a>b){ max = a; }else{ max = b; } 不过,C语言提供了一种更加简单的方法,叫做条件运算符,语法格 ...
- 四、Android Studio使用——什么样的Project都能导入Studio
1 导入Github源码(别人的Studio工程) 导入之前先看下(导入的工程)gradle-wrapper.properties文件里的gradle-版本是多少. 然后如果这个文件中的版本和你AS工 ...
- 动态规划——最长公共上升子序列LCIS
问题 给定两个序列A和B,序列的子序列是指按照索引逐渐增加的顺序,从原序列中取出若干个数形成的一个子集,若子序列的数值大小是逐渐递增的则为上升子序列,若A和B取出的两个子序列A1和B1是相同的,则A1 ...
- JZOJ.5288【NOIP2017模拟8.17】球场大佬
Description 每天下午,古猴都会去打羽毛球.但是古猴实在是太强了,他必须要到一些比较强的场去打.但是每个羽毛球场都有许多的人排着队,每次都只能上四个人,每个人都有自己的能力值,然 ...
- <link>标签的rel属性全解析
<link>标签定义了当前文档与 Web 集合中其他文档的关系.link 元素是一个空元素,它仅包含属性.此元素只能存在于 head 部分,不过它可出现任何次数.在 HTML 中,&l ...
- 按批次处理list数据 (list按条数取)
按批次处理list数据的两种方法 主要应用于list存储数据过多,不能使list整体进行其余操作 Java | 复制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...
- ArcEngine之Provide your license server administrator with the following information.error code =-42
今天打开VS,不一会就出现了下面的对话框,感到非常疑惑,仔细一想,原来是昨天不小心把权限弄错了! 解决办法:在控价中找到AxLicenseControl,右键属性,把权限改为ArcGIS Engine ...
- util 常用方法
C:\Program Files\Java\jdk1.8.0_171\src.zip!\java\lang\System.java /** * Returns the current time in ...
- echarts学习心得1---模块化单文件引入和标签式单文件引入
一.模块化单文件引入 1. 为ECharts准备一个具备大小(宽高)的Dom(当然可以是动态生成的) <div id="main" style="height:40 ...
- 设计模式之——Template模板模式
Template模式又叫模板模式,是在父类中定义处理流程的框架,在子类中实现具体处理逻辑的模式.当父类的模板方法被调用时程序行为也会不同,但是,不论子类的具体实现如何,处理的流程都会按照父类中所定义的 ...