跟小静读CLR via C#(02)-基元类型、引用类型、值类型

一、 基元类型

编译器能够直接支持的数据类型叫做基元类型。例如int, string等。基元类型和.NET框架类库FCL存在着直接的映射关系。

string和String

面试的时候曾经被问到过这个问题,C#中的基元类型string实际上对应了System.String(FCL)类型,所以两者使用的时候没有什么不同。

类型转换

编译器能够在基元类型之间进行显式或隐式转换。如果转换是安全的,也就是转换过程不会造成数据丢失,则可以直接采用隐式转换。如果是不安全的,则必须采用显式转换。

Int32 a=5;

Int64 b=a;

Int32 c=(Int32)b;

二、 引用类型和值类型

引用类型和值类型的区别:

引用类型

值类型

从托管堆中分配

从线程的堆栈中分配

对象考虑垃圾回收机制

不考虑垃圾回收机制

所有类都是引用

结构或枚举都是值类型

继承自System.ValueType

只有装箱形式

有两种形式:装箱和未装箱

可以继承和派生

不能作为基类,不能有虚方法

引用类型变量初始化时默认为null

初始化时默认为0值

复制时只拷贝内存地址

复制时“字段对字段”的拷贝

   

结构体直接继承自System.ValueType;而枚举直接继承自System.Enum, Enum类又直接继承自System.ValueType。

下面通过例子看一下他们的区别:

首先定义类和结构体:

class SomeRef { public Int32 x; }

struct SomeVal { public Int32 x; }

SomeRef r1 = new SomeRef(); // 分配到堆

SomeVal v1 = new SomeVal(); // 分配到栈

r1.x =5; // 所引用的堆空间内数据修改

v1.x =5; // 直接在栈上复赋值

Console.WriteLine(r1.x); // "5"

Console.WriteLine(v1.x); // "5"

SomeRef r2 = r1; //只把指针复制给了r2

SomeVal v2 = v1; // 在栈上分配空间,并且将变量内容进行复制

r1.x = 8; // r1指向(也是r2指向)的内容修改

v1.x = 9; // 只修改v1内容,v2内容不会受影响

Console.WriteLine(r1.x); // "8"

Console.WriteLine(r2.x); // "8"

Console.WriteLine(v1.x); // "9"

Console.WriteLine(v2.x); // "5"

看看下图的内存分配情况,就一目了然了。

三、 值类型的装箱与拆箱

1. 装箱过程?

装箱:将值类型转换为引用类型。当我们把值类型参数传递给需要引用类型参数的方法时,会自动进行装箱操作。过程如下:

  • 从托管堆为要生成的引用类型分配大小。大小为:值类型实例本身的大小+额外空间(方法表指针和SyncBlockIndex)。
  • 将值类型字段拷贝到刚刚分配的内存中。
  • 返回托管堆中新分配内存的地址。也就是指向对象的引用。

2. 拆箱过程?

拆箱:获取指向对象中包含的值类型部分的指针。一般拆箱之后会进行字段拷贝操作,两个操作加起来才是真正与装箱互反的操作。过程如下:

  • 如果引用为Null,则抛出NullReferenceException异常。
  • 如果引用对象不是一个期望值类型的已装箱对象,会抛出InvalidCastException异常。
  • 返回一个指向包含在已装箱对象中值类型部分的指针。

3. 实例

  • 拆箱的转型结果必须是它原来未装箱时的类型。

public static void Main() {

Int32 x = 5;

Object o = x; // 装箱

Int16 y = (Int16) o; // 拆箱,抛出InvalidCastException异常

}

修正:Int16 z=(Int16)(Int32)o;//拆箱成功

  • 这段代码进行了几次装箱?

public static void Main() {

Int32 v = 5; // 创建值变量

Object o = v; // 装箱

v = 123; // Changes the unboxed value to 123

Console.WriteLine(v + ", " + (Int32) o); // Displays "123, 5" ,装箱两次

}

上面的代码进行了3次装箱,最后一行中v被装箱为引用类型,o首先被拆箱然后再装箱为引用类型。

我们看一下它的IL代码:

字符串连接实际上调用的是Concat方法,该方法的参数要求是object,因此各参数都要转换成object类型。

优化:

Console.WriteLine(v.ToString()+”,”+o);//装箱0次

我们要尽量少的进行值类型的装箱拆箱操作,以提高程序性能。

跟小静读CLR via C#(02)-基元类型、引用类型、值类型相关推荐

  1. 跟小静读CLR via C#-开篇及目录

    最近正在拜读Jeffrey大师的.NET巨作-<CLR via C#>.好书就像一杯茶,需要静下心来慢慢品.在写笔记的过程中,也加入了自己的思考:在和园友们的交流中,理解也不断的加深. 目 ...

  2. 跟小静读CLR via C#(05)- 访问限定、数据成员

    跟小静读CLR via C#(05)- 访问限定.数据成员 今天跟大家分享一下关于访问限定和数据成员的知识.主要包括以下两点: Abstract, sealed, virtual, new, over ...

  3. 跟小静读CLR via C#(06)- 构造器

    跟小静读CLR via C#(06)- 构造器 最近忙着看新还珠,好几天不学习了.玩物丧志啊,罪过罪过. 今天总结的是类构造器的知识,其实这方面的文章蛮多的,可还是觉得亲自写一下对自己的思考和认识会有 ...

  4. 跟小静读CLR via C#(18)——Enum

    1. Enum定义 枚举类型是经常用的一种"名称/值"的形式,例如: public enum FeedbackStatus      {          New,         ...

  5. 跟小静读CLR via C#(16)--泛型

    泛型就像是一个模板,常常定义一些通用的算法,具体调用时再替换成实际的数据类型,提高了代码的可重用性. 一.初识泛型 1. 简单实例 以最常用的FCL中的泛型List<T >为例: stat ...

  6. 跟小静读CLR via C#(10)-参数

    最近几天学了参数,其实对于参数本不陌生,从上学学C语言基础的时候就学过了.不过细心学下来,还是收获了一些. 一. 命名参数.可选参数 命名参数和可选参数是在Visual C#2010中引入的新特性. ...

  7. 跟小静学CLR via C#(12)-委托Delegate

    本来按照进度应该学习事件了,可总觉得应该委托在前,事件在后,才好理解. 委托是一个类,它提供了回调函数机制,而且是类型安全的.使用委托可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数 ...

  8. 跟小静读《jQuery权威指南》——目录

    前言 2014年开始了,年底给自己制订的学习计划,第一步先从学习<jQuery权威指南>开始. jQuery大家都很比较熟悉,但是我经常是边用的时候边对照着API,这次找本书通读一遍,记录 ...

  9. 【深入理解CLR 六】基元类型、引用类型和值类型

    最近工作的事情比较忙,导致CLR很久没有更新了,恰巧周五听了涛涛的关于GC和内存管理的技术分享,想了下自己对CLR的学习得跟上,另外之前武哥推荐了一本书叫<码农翻身>,是一个IBM架构师写 ...

最新文章

  1. Bazel入门教程:编译C++项目
  2. Character流与Byte流的区别
  3. Nilearn中的Matplotlib颜色图
  4. [转载]交换机背板带宽计算方法
  5. jstl标签的用法 fn标签
  6. 【数字信号处理】傅里叶变换性质 ( 频域函数的共轭对称分解 | 序列的傅里叶变换 | 傅里叶变换的共轭对称 | 傅里叶变换的共轭反对称 )
  7. jodd-StringTemplateParser使用
  8. Java未被捕获的异常
  9. python刷题总结_【python刷题】差分数组
  10. 转:传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确 .
  11. Kerberos 基本命令 - 持续更新
  12. 【转载】IDEA中Git的更新/提交/还原方法
  13. 如何正确使用广告素材、优化Facebook广告
  14. Android,EditText,InuputType
  15. 查询各个商品分类中各有多少商品的SQL语句
  16. 《Mastering opencv....读书笔记》基于标记的虚拟现实
  17. Google拒绝因搜索不良信息被传唤
  18. 高并发架构系列:最全消息队列有哪些?详解消息队列的选型与应用
  19. 尾纤SC、ST、FC、LC区分
  20. 3.6 矩阵秩的其它重要关系

热门文章

  1. java mybatis向mysql数据库插入中文出现乱码
  2. 《Nmap渗透测试指南》—第6章6.4节IP欺骗
  3. 创建Okhttp自定义Log
  4. 数据挖掘过程中:数据预处理
  5. Web前端上万字的知识总结
  6. php 实例说明 socket通信机制
  7. JavaScript速记
  8. 小白的 --Vuex 入门理解
  9. 阿里巴巴公布第二财季报告,净利润同比增长71%
  10. redis数据结构之一:链表