博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C# 值类型和引用类型
阅读量:6345 次
发布时间:2019-06-22

本文共 2108 字,大约阅读时间需要 7 分钟。

一、基本概念

C#只有两种数据类型:值类型和引用类型

值类型在线程栈分配空间,引用类型在托管堆分配空间

值类型转为引用类型称成为装箱,引用类型转为值类型称为拆箱

以下是值类型和引用类型对照表

从上图可以简单看出:string,Object,数组,class是引用类型,简单类型,枚举,结构是值类型。

二、代码展示

定义一个类和结构调用赋值

内存分配情况如下图:

从这张图可以看出,class实例化出来的对象,指向了内存堆中分配的空间;truct实例化出来的对象,是在内存栈中分配。

修改代码如下:

内存分配情况:

由上图可以知:

object obj=”abc”;  string i=(string)obj;

值类型和引用类型储的位置不一样

如果是引用类型,当两个对象指向同一个地方,修改某一个的时候,其它对象的值会发生改变

注意点:

1、值类型变量做为局部变量时,该实例将被创建在堆栈上;而如果值类型变量作为类型的成员变量时,它将作为类型实例数据的一部分,同该类型的其他字段都保存在托管堆上。

2、引用类型变量数据保存在托管堆上,但是根据实例的大小有所区别:当实例的大小小于85000Byte时实例将创建在GC堆上;当实例大小>=85000byte时,则该实例创建在LOH(Large Object Heap)堆上。

using System;namespace ConsoleApplication2{    //引用类型(因为‘class’)    public class SomeRef    {        public int x { get; set; }    }    //值类型(因为‘struct’)    public struct SomeVal    {        public int x{ get; set; }    }    class Program    {        static void Main(string[] args)        {            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;  //只复制引用(指针)            SomeVal v2 =v1;  //在栈上分配并赋值成员            r1.x = 8;       //r1.x和r2.x都会修改            v1.x = 8;       //v1.x会更改,v2.x不会            Console.WriteLine(r1.x); //显示8              Console.WriteLine(r2.x); //显示8              Console.WriteLine(v1.x); //显示8            Console.WriteLine(v2.x); //显示5            Console.ReadKey();        }    }}
图片上的代码

 

二、值类型装箱、拆箱

1、装箱:就是将值类型的数据打包到引用类型的实例中( 比如将int类型的值1赋给object对象obj)

int  i=1;  object obj=(object)i;

 装箱时到底发生的事情:

1)、在托管堆中分配内存。分配的内存量是值类型各字段所需的内存量,还要加上托管堆所有对象都有的两个额外成员(类型对象指针和同步块索引)所需的内存量

2)、值类型的字段复制到新分配的堆内存

3)、返回对象地址,现在该地址是对象引用;值类型成了引用类型

2、拆箱:就是从引用数据中提取值类型(比如将object对象obj的值赋给int类型的变量i)

object obj=”1”;  int i=(int)obj;

拆箱不是装箱过程倒过来,拆箱的代价要比装箱低的多,拆箱是获取指针的过程,该指针指向包含在一个对象中的原始值类型。

拆箱后将堆中的字段包含的值复制栈的值类型实例中。

3、值类型变为引用类型不一定要装箱,例如:

string str = "joye.net" + 26;   //需要将26装箱为string类型string str1 = "joye.net" + 26.ToString(); //tostring后不需要装箱

感兴趣的可以用IL看一下。

三、参考资料

  《深入理解C#》第二版

  《CLR VIA C#》第四版

  《C# 高级编程》第四版

  还有很多网络上的文章,就不一一例举了

转载地址:http://umcla.baihongyu.com/

你可能感兴趣的文章
linux内核--自旋锁的理解
查看>>
银行卡的三个磁道
查看>>
OpenSSL 提取 pfx 数字证书公钥与私钥
查看>>
Keepalived详解(四):通过vrrp_script实现对集群资源的监控【转】
查看>>
CollapsingToolbarLayoutDemo【可折叠式标题栏,顺便带有CardView卡片式布局】
查看>>
CentOS7.4安装配置mysql5.7 TAR免安装版
查看>>
解决IE二级链接无法打开故障
查看>>
Windows phone应用开发[16]-数据加密
查看>>
SQL Server 迁移数据到MySQL
查看>>
通用数据压缩算法简介
查看>>
The next Industry Standard in IT Monitoring, a python implementation Nagios like tool --- Shinken
查看>>
(笔记)找工作,该怎么进补
查看>>
div的显示和隐藏以及点击图标的更改
查看>>
(轉貼) Ubuntu將在ARM平台netbook上現身 (SOC) (News) (Linux) (Ubuntu)
查看>>
SQL注入测试工具:Pangolin(穿山甲)
查看>>
在html 的img属性里只显示图片的部分区域(矩形,给出开始点和结束点),其他部份不显示,也不要拉伸...
查看>>
程序员第二定律:量化管理在程序员身上永无可能
查看>>
ubuntu一些脚本的执行顺序
查看>>
类继承的结构
查看>>
Intel 被 ARM 逼急了
查看>>