目前在看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
}

第一部分执行完(上一节讲到变量是在序幕代码中进行初始化到栈中):

全部执行完:


装箱和拆箱

这里将一个苹果比喻成值类型,见到苹果能知道他就是吃的苹果,苹果有多种品种(结构和枚举)。

把一个纸箱比喻成引用类型,纸箱可以装各种各样的东西(各种类)。

装箱:将值类型转换为一个引用类型

把苹果装进纸箱(在内存中是复制),就是装箱。装箱运输的话,苹果要仔细打包,很小心。

装箱步骤

  1. 在托管堆上分配内存,内存大小为值类型所有字段的大小和类型对象指针加上同步块索引的大小。
  2. 将值类型的所有字段复制到刚分配的内存中。
  3. 返回刚分配的内存地址

拆箱:将引用类型转换成值类型

拆箱可能就直接用小刀划开胶带,然后看见苹果(这里已经完成了拆箱),接着取出苹果(在内存中是复制)。

拆箱不是直接把装箱过程倒过来,拆箱的代价要比装箱低的多。拆箱其实就是一个获取指针的过程。不要求在内存中复制任何字节。

拆箱步骤

  1. 获取引用类型所有字段对应的地址,这里拆箱已经完成了。
  2. 拆箱操作完成后,会发生一次字段的复制。

来看个例子

   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基础二】浅谈引用类型、值类型和装箱、拆箱的更多相关文章

  1. NET中的类型和装箱/拆箱原理

    谈到装箱拆箱,DebugLZQ相信给位园子里的博友一定可以娓娓道来,大概的意思就是值类型和引用类型的相互转换呗---值类型到引用类型叫装箱,反之则叫拆箱.这当然没有问题,可是你只知道这么多,那么Deb ...

  2. 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 ...

  3. js包装类型的装箱拆箱

    https://www.jb51.net/article/155820.htm https://juejin.im/post/5cbaf130518825325050fb0a https://juej ...

  4. c#基础系列1---深入理解值类型和引用类型

    "大菜":源于自己刚踏入猿途混沌拾起,自我感觉不是一般的菜,因而得名"大菜",于自身共勉. 不知不觉已经踏入坑已10余年之多,对于c#多多少少有一点自己的认识, ...

  5. C#基础知识1-深入理解值类型和引用类型

    C#值类型和引用类型这个概念在刚学习的时候应该就知道了.但是我们并没有深入的去理解它.越是基础知识其实才是最有用的.对代码的优化,代码质量的提升都有帮助.通过整理本文章,对很多知识也起到了巩固的作用吧 ...

  6. 【深入理解CLR】2:细谈值类型的装箱和拆箱

    装箱 总所周知,值类型是比引用类型更“轻型”的一种类型,因为它们不作为对象在托管堆中分配,不会被垃圾回收,也不通过指针来引用.但在许多情况下,都需要获取对值类型的一个实例的引用.例如,假定要创建一个A ...

  7. [CLR via C#]5.3 值类型的装箱和拆箱

    原文:[CLR via C#]5.3 值类型的装箱和拆箱 在CLR中为了将一个值类型转换成一个引用类型,要使用一个名为装箱的机制. 下面总结了对值类型的一个实例进行装箱操作时内部发生的事: 1)在托管 ...

  8. Windows Phone 开发起步之旅之二 C#中的值类型和引用类型

    今天和大家分享下本人也说不清楚的一个C#基础知识,我说不清楚,所以我才想把它总结一下,以帮助我自己理解这个知识上的盲点,顺便也和同我一样不是很清楚的人一起学习下.  一说起来C#中的数据类型有哪些,大 ...

  9. C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)

    一:值类型和引用类型的含义参考前一篇文章 C#学习笔记(基础知识回顾)之值类型和引用类型 1.1,C#数据类型分为在栈上分配内存的值类型和在托管堆上分配内存的引用类型.如果int只不过是栈上的一个4字 ...

随机推荐

  1. Linux中使用SecureCRT上传、下载文件命令sz与rz用法实例

    来自:http://www.jb51.net/LINUXjishu/163820.html 其中,对于sz和rz的理解与记忆我用了如下的方法(因为很多时候容易搞混):sz中的s意为send(发送),告 ...

  2. phpcms V9内容页调用标签

    1.页面标题:{$title} 2.发表时间:{$inputtime} 3.内容来源:{$copyfrom} 4.文章内容:{$content} 5.缩略图地址:{$thumb} 6.组图列表: {l ...

  3. Java使用BigDecimal解决浮点型运算丢失精度的问题

    @Test public void test1(){ System.out.print(0.05+0.01); } @Test public void test2(){ BigDecimal b1 = ...

  4. Java 调用并执行cmd命令

    cmd java 调用 执行 概要: Java 调用并执行cmd命令 Java | 复制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 2 ...

  5. Python全栈day17(文件处理)

    一,文件处理流程 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 二,文件打开模式 r只读 (默认打开模式是只读) w只写 a追加 三,文件操作实例 1.r读 read读取文 ...

  6. FZU 2144 Shooting Game (贪心区域划分)

    Problem 2144 Shooting Game Accept: 370 Submit: 1902 Time Limit: 1000 mSec Memory Limit : 32768 KB Pr ...

  7. (转)Java DecimalFormat 用法(数字格式化)

    我们经常要将数字进行格式化,比如取2位小数,这是最常见的.Java 提供 DecimalFormat 类,帮你用最快的速度将数字格式化为你需要的样子.下面是常用的例子: import java.tex ...

  8. combined with the Referer header, to potentially build an exhaustive data set of user profiles and browsing habits Client Identification

    w https://www.zhihu.com/question/35307626 w 0-客户端(附加用户信息)首次请求服务端--->服务端生成session(有唯一性).session_id ...

  9. python基础-第十篇-10.1HTML基础

    htyper text markup language 即超文本标记语言 超文本:就是指页面内可以包含图片.链接,甚至音乐,程序等非文字元素 标记语言:标记(标签)构成的语言 网页==HTML文档,由 ...

  10. 剑指Offer——左旋转字符串

    题目描述: 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S=”ab ...