C#中值类型和引用类型

本文将介绍C#类型系统中的值类型和引用类型,以及两者之间的一些区别。同时,还会介绍一下装箱和拆箱操作。

值类型和引用类型

首先,我们看看在C#中哪些类型是值类型,哪些类型是引用类型。

值类型:

  • 基础数据类型(string类型除外):包括整型、浮点型、十进制型、布尔型。  

    • 整型(sbyte、byte、char、short、ushort、int、uint、long、ulong )
    • 浮点型(float 和 double )
    • 十进制型(decimal )
    • 布尔型(bool )
  • 结构类型(struct)
  • 枚举类型(enum)

引用类型:

  • class、interface、delegate、object、string、Array

默认值

变量的初始化中,都会有一个默认值,在C#中,我们可以通过default关键字去查看某个类型的默认值。

通过default(int)可以看到,int的默认值是0,default(bool)显示布尔类型的默认值是false。

对于所有的引用类型,默认值都会是null。

注意,这里有个特殊的情况就是结构struct,如果对一个结构进行default操作,我们将得到每个结构成员的初始值状态。也就是说,值类型成员赋予值类型的默认值,引用类型成员赋予引用类型的默认值。

简单对比值类型和引用类型

下面,我们通过一个简单的例子看看。假设有一个Point类型,有x和y两个坐标成员。

同样是下面一段代码

Point p1 = new Point(5,9);
Point p2 = p1;

如果Point类型是通过结构struct实现,那么p2将会是p1的一个副本,也就是说任何一个的修改都不会影响另外一个;如果Point类型是通过类class实现,那么p2和p1的引用值将会指向同一个对象。

为了进一步了解值类型和引用类型,我们需要介绍一下栈和堆这两个基本概念。

栈和堆

当我们在32为系统上运行一个程序的时候,这个程序就会有一个4GB的进程运行空间。我们所要讨论的栈和堆就存放在这个4GB的空间中。

栈和堆的简介

在C#中,栈(Stack)是指堆栈;堆(Heap)是指托管堆,由.NET垃圾收集器自动管理。

这里就不对栈和堆进行详细的分析了,只是举一个简单的例子来大致描述栈和堆的工作原理。

从图中可以看到,局部变量在栈上的变化(入栈),当函数执行结束后,栈上的空间将会被清理;但是我们在堆上分配的空间始终从在,只能等待GC去帮我们清理不会被引用到的空间。

值类型和引用类型的存放

介绍过栈和堆之后,下面我们看看值类型和引用类型是怎么存放的。

对于值类型的变量,这个变量本身就代表这个值类型的值;但是,对于引用类型的变量,这个引用类型的实例是在托管堆上分配的空间,而这个变量本身只是代表一个指向托管堆实例的引用(指针)

所以这里,我们可以对值类型和引用类型变量的存储有两个概括:

  • 引用类型永远存储在堆里
  • 值类型和引用(指针)永远存储在它们声明时所在的堆或栈里
    • 如果一个值类型不是在方法中定义的,而是在一个引用类型里,那么此值类型将会被放在这个引用类型里并存储在堆上

注意:根据上面第二点概括,可以得到"值类型一定存储在栈中"这个说法是错误的。例如,我们有一个Student类,在这个类中的Age属性是一个值类型,但是这个值类型是存储在Student类实例的空间中,也就是在堆上。

class Student
{
    public string Name { get; set; }
    public int Age{ get; set; }
} 

装箱和拆箱

由于C#中所有的数据类型都是由基类System.Object继承而来的,所以值类型和引用类型的值可以通过显式(或隐式)操作相互转换。

这里,可以将装箱和拆箱描述为:

  • 装箱是将值类型转换为引用类型
  • 拆箱是将引用类型转换为值类型

装箱/拆箱的内部操作

其实,在装箱和拆箱的过程中都对应一系列的转换,这里就通过下图表示了。

在值类型进行装箱时,生成的是全新的引用对象,这会有时间损耗,也就是造成效率降低。所以在C# 2.0中就引入了泛型来减少装箱操作和拆箱操作消耗。

总结

本文介绍了C#中的值类型和引用类型,以及栈和堆的基本概念。然后分析了值类型和引用类型在栈和堆中的存放。

同时,我们也了解到了:

  • 当使用引用类型时,我们是在和指向引用类型的引用(指针)打交道,而不是引用类型本身
  • 当使用值类型时,我们是在和值类型本身打交道
时间: 2024-10-12 01:48:19

C#中值类型和引用类型的相关文章

Java中值类型与引用类型

JAVA中值类型和引用类型的不同? 1.定义 引用类型表示你操作的数据是同一个,也就是说当你传一个参数给另一个方法时,你在另一个方法中改变这个变量的值,那么调用这个方法是传入的变量的值也将改变:值类型表示复制一个当前变量传给方法,当你在这个方法中改变这个变量的值时,最初生命的变量的值不会变.通俗说法: 值类型就是现金,要用直接用:引用类型是存折,要用还得先去银行取现. 2.分类 (1)值类型 值类型也就是基本数据类型 基本数据类型常被称为四类八种. 四类:1.整型 2.浮点型 3.字符型4.逻辑

C#中值类型和引用类型的区别浅记

C#中值类型和引用类型的区别浅记 在C#中,变量的类型分为两种,分别是值类型和引用类型. 值类型的变量直接存储值,说得更具体一些,就是值类型变量在内存中直接存储它们自身的值,如代码所示, int x = 2: 值类型变量x,在内存中的某处直接存储了它自身的值:2. 引用类型的变量存储的是对其对象的引用,更进一步说,就是引用类型变量在内存中直接存储了一个指向它处的引用,而引用所指的对象则保存在引用类型变量所指的内存中.如代码所示, public class Thing { int x; } Thi

内存角度看c#中值类型和引用类型的区别(转)

1.    值类型的数据存储在内存的栈中:引用类型的数据存储在内存的堆中,而内存单元中只存放堆中对象的地址. 2.     值类型存取速度快,引用类型存取速度慢. 3.     值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针或引用 4.     值类型继承自System.ValueType,引用类型继承自System.Object 5.     栈的内存分配是自动释放:而堆在.NET中会有GC来释放 6.      值类型的变量直接存放实际的数据,而引用类型的变量存放的则是数据的

Java中值类型和引用类型的区别

[定义] 引用类型表示你操作的数据是同一个,也就是说当你传一个参数给另一个方法时,你在另一个方法中改变这个变量的值, 那么调用这个方法是传入的变量的值也将改变.值类型表示复制一个当前变量传给方法, 当你在这个方法中改变这个变量的值时,最初生命的变量的值不会变.通俗说法: 值类型就是现金,要用直接用:引用类型是存折,要用还得先去银行取现.----(摘自网上) [值类型] 也就是基本数据类型 基本数据类型常被称为四类八种 四类: 1,整型 2,浮点型 3,字符型4,逻辑型 八种: 1,整型3种 by

.Net中值类型和引用类型的区别

解析:CLR支持两种类型:值类型和引用类型.用Jeffrey Richter(<CLR via C#>作者)的话来说,"不理解引用类型和值类型区别的程序员将会把代码引入诡异的陷阱和诸多性能问题".这就要求我们正确理解和使用值类型和引用类型. 值类型包括C#的基本类型(用关键字int.char.float等来声明),结构(用struct关键字声明的类型),枚举(用enum关键字声明的类型):而引用类型包括类(用class关键字声明的类型)和委托(用delegate关键字声明的

JS中值类型和引用类型

一.值类型 例子: 1 var a=10; 2 var b=a; 3 a=20; 4 console.log(b); //10 例子中,将a的值赋给了b,b=10,然后改变a的值不会影响b的值,a和b是独立的两份,互不影响. 二.引用类型 例子: 1 var a={age:10}; 2 var b=a; 3 b.age=20; 4 console.log(a.age); //20 例子中,a和b同时指向一个对象,即 {age:10} ,a和b互相影响,所以当改变其中一个值时,另一个也相应改变 引

.Net中值类型和引用类型

装箱 就是把“值类型”转换成“引用类型”(Object): 拆箱 就是把“引用类型”转换成“值类型”: 引用类型:基类为Objcet 值类型:均隐式派生自System.ValueType: 值类型:byte,short,int,long,float,double,decimal,char,bool 和 struct 统称为值类型 引用类型:string 和 class统称为引用类型. 说起值类型和引用类型就会说到堆和栈的问题,那什么是堆什么是栈呢?他们之间又有什么区别的呢? https://ww

java中值类型和引用类型的不同实例(一)

简单分类,java中除了值类型就是对象.值类型就是java中的基本类型,而除了这些基本类型都是对象. [内存] “一个具有值类型(value type)的数据存放在栈内的一个变量中.即是在栈中分配内存空间,直接存储所包含的值,其值就代表数据本身. 值类型的数据具有较快的存取速度. 一个具有引用类型(reference type)的数据并不驻留在栈中,而是存储于堆中.即是在堆中分配内存空间,不直接存储所包含的值,而是指向所要存储的值,其值代表的是所指向的地址.当访问一个具有引用类型的数据时,需要到

C#中值类型和引用类型的区别

1.    值类型的数据存储在内存的栈中:引用类型的数据存储在内存的堆中,而内存单元中只存放堆中对象的 地址. 2.     值类型存取速度快,引用类型存取速度慢. 3.     值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针或引用 4.     值类型继承自System.ValueType,引用类型继承自System.Object 5.     栈的内存分配是自动释放:而堆在.NET中会有GC来释放 6.      值类型的变量直接存放实际的数据,而引用类型的变量存放的则是数据