首页 > 其他分享 >值类型和引用类型

值类型和引用类型

时间:2024-07-16 22:09:25浏览次数:14  
标签:存储 String 内存 类型 数据 引用

值类型和引用类型

栈和堆

程序运行时,它的数据必须存储在内存中。一个数据项需要多大的内存、存储在什么地方、以及如何存储都依赖于该数据项的类型

运行中的程序使用两个内存区域来存储数据:栈和堆

  1. 定义:栈是一个内存数组,是一个LIFO(Last_In First_Out)后进先出的的数据结构。栈存储几种类型的数据:

  • 某些类型变量的值;

  • 程序当前的执行环境

  • 传递给参数的方法

我们可以简单的把栈形象地看成一筒羽毛球,当往筒里放球时,球从筒底排到筒口,当从筒里拿球的时候,球从筒口往下依次被拿出来,直到筒底的最后一个球被拿出来。

羽毛球

  1. 操作 栈有如下几个特征:

  • 数据只能从栈的顶端插入和删除

  • 向栈中添加元素,此过程被称为"进栈"(入栈或压栈);

  • 从栈中提取出指定元素,此过程被称为"出栈"(或弹栈);

系统管理所有的栈操作。作为程序员,你不需要显式地对它做任何事情。但了解栈的基本功能可以更好地了解程序在运行时正在做什么,并能更好地了解C#文档和著作。

栈 入栈 出栈

堆是一块内存区域,在堆里可以分配大块的内存用于存储某类型的数据对象。与栈不同,堆里的内存能够以任意顺序存人和移除。如图所示一个堆里存放四个数据

内存堆

虽然程序可以在堆里保存数据,但并不能显式地删除它们。CLR的自动GC(GarbageCollector,垃圾收集器)在判断出程序的代码将不会再访问某数据项时,自动清除无主的堆对象。我们因此可以不再操心这项使用其他编程语言时非常容易出错的工作了。如图阐明了垃圾收集过程。

堆中的自动垃圾收集

值类型和引用类型

数据项的类型定义了存储数据需要的内存大小及组成该类型的数据成员。类型还决定了对象在内存中的存储位置--栈或堆。

类型被分为两种:值类型引用类型,这两种类型的对象在内存中的存储方式不同。

  • 值类型只需要一段单独的内存,用于存储实际的数据。

  • 引用类型需要两段内存。

    • 第一段存储实际的数据,它总是位于堆中。

    • 第二段是一个引用,指向数据在堆中的存放位置。

如图展示了每种类型的单个数据项是如何存储的。对于值类型,数据存放在栈里。对于引用类型,实际数据存放在堆里而引用地址存放在栈里。

数据存储

下表中列出了C#中所有的类型以及他们的类别:值类型或引用类型。 CSharp中的值类型和引用类型

值类型和引用类型的区别

  1. 值类型存取速度快,引用类型存取速度慢。

  2. 值类型表示实际数据,引用类型表示存储在堆中的数据的引用和地址。

  3. 值类型都继承自System.ValueType,引用类型都继承自System.Object。

  4. 栈中的内存是自由分配自动释放的,而引用类型会由.NET的GC来回收释放。

 

 

引用类型和值类型调用

 

1.引用类型

假设有一个引用类型的实例,名称为student,它有两个成员:一个值类型成员和一个引用类型成员。它将如何存储呢?是否是值类型的成员存储在栈里,而引用类型的成员如上图所示的那样在栈和堆之间分成两半呢?答案是否定的。

请记住,对于一个引用类型,其实例的数据部分全部存放在堆里。既然两个成员都是对象数据的一部分,那么它们都会被存放在堆里,无论它们是值类型还是引用类型。

对于引用类型的任何对象,它所有的数据成员都存放在堆里,无论它们是值类型还是引用类型。 引用类型存储

 

值类型的变量存储的是值本身(存储到栈中) 引用类型的变量存储的是数据的内存地址(存储到堆中,变量保存的是内存地址) = 运算符在进行复制操作的时候,复制的是被复制变量栈中存储的内容 = 进行赋值操作的时候,操作的也是栈中存储的内容 数据类型区别_1

数据类型区别_2

 int a = 1;
 int b = a;
 a = 2;
 Console.WriteLine(a);//2
 Console.WriteLine(b);//1
 ​
 ​
 ​
 Book book1 =new Book();
 book1.Name = "西游记";
 book1.Price = 100;
 ​
 Book book2 = book1;
 ​
 book1.Name = "红楼梦";
 Console.WriteLine(book1.Name);//红楼梦
 Console.WriteLine(book2.Name);//红楼梦
 ​
 class Book
 {
     public string Name;
     public float Price;
 }

2. String

在 C# 中,string 类型被视为引用类型。但是,与其他引用类型不同的是,对 string 变量的操作被视为对值类型的操作,因此,在对 string 变量进行赋值或传递到方法时,其实是进行值传递。

这意味着,当您将一个字符串变量传递给一个方法时,该方法会接收该字符串的一个副本,而不是原始字符串的引用。任何对传递的字符串副本的修改都不会影响原始字符串。

值类型和引用类型的区别在于,值类型存储在栈中,而引用类型存储在堆中。当您创建一个字符串变量时,它实际上是一个引用类型,但是 .NET 框架会将其优化为值类型,以提高性能。

需要注意的是,字符串是不可变的,即一旦创建就无法更改。因此,在对字符串进行操作时,实际上是创建了一个新的字符串对象,而不是修改原始字符串对象。这也是为什么 C# 中的字符串变量是值传递的原因。

总之,在 C# 中,string 类型是引用类型,但是在对其进行操作时,会被视为值类型,因此是值传递的。

 String str1 = "123";
 String str2 = str1;
 str2 = "321";
 Console.WriteLine(str1)
 ​
 // output: "123"

 

上面代码的最终输出结果是123,上面刚讲过引用类型的调用,同学一定会问:str2不是在存储的是str1的引用么?那么str2不是和str1指向堆中同一块内存空间么?为什么在引用了str2使其改变数据后再打印出str1最终还是打印出来123?

在c#中,String的存储方式很特殊,在c#的内存中,在常量区里会分配一块空间叫做String暂存池(常量池),在某些时候,我们的字符串数据是存储在这个常量池中的,而地址依然是存放在栈中。

例如用 String str = "XXXX" 的方式来创建String变量的话,那么String的值便会存储在String常量池中,在我们以这种方式创建String变量时,编译器会先判断你这个内容有没有已经在常量池出现过了,如果已经出现过,那么不会再在常量池中使用空间来存放一个相同的内容,这个内容只会固定有一个引用,所以在创造相同内容的String的时候,他们的引用都是相同的。又有一种情况:一开始A和B内容相同,就是说A与B的引用都相同时,此时将B的内容更改,那么B的内容在常量池中就会使用另一块空间,那么相应的B的引用也会改变,而A的引用并不会改变,因为A此时还是存储的原来的内容。我们可以来看简易的图解: stringA=stringB

stringA=ABCD

标签:存储,String,内存,类型,数据,引用
From: https://www.cnblogs.com/Honsen/p/18306224

相关文章

  • 关于静态文件目录与模板引用和Nginx location块的适配设置
    项目配置文件内关于静态文件的设置项#静态文件的URL前缀STATIC_URL='/static/'#项目根目录的静态文件目录STATICFILES_DIRS=[os.path.join(BASE_DIR,'static'),os.path.join(BASE_DIR,'parallel/static'),os.path.join(BASE_DIR,'blog/static&#......
  • C语言中的整数类型及其类型转换
    C语言中的整数数据类型C语言中的整型数据就是定点整数,根据位数的不同,可分为字符型(char,8位)、短整型(short或shortint,16位)、整型(int,32位)、长整型(long或longint,在32位机器中为32位,在64位机器中为64位)。char是整型数据中比较特殊的一种,其他如short/int/......
  • 整型,浮点型,字符型数据类型学习
    整型数据整型常量表示:在C语言中,有三种形式:           十进制整数如:123、-123八进制整数以0开头的数,如0123表示八进制数123十六进制整数以0x开头的数,如0x123表示十六进制数123整型变量:    数据在内存中以二进制形式存放。    数值以......
  • Java基础之数据类型扩展
    一、整数扩展Java中四种进制的表示方式:二进制0b,八进制0,十进制默认,十六进制0x或0XpublicclassDemon02{publicstaticvoidmain(String[]args){//二进制inti=0b10;//八进制inti2=010;//默认十进制i......
  • 2024-07-16 使用了.md文件作为路由文件来引用,在开发中能正常显示,打包的时候就报错了:Ca
    我使用了.md文件作为路由文件来引用,在开发中能正常显示,打包的时候就报错了//vite.config.ts import{defineConfig}from'vite'; importvuefrom'@vitejs/plugin-vue'; importmarkdownfrom"vite-plugin-md"; exportdefaultdefineConfig({  plugin......
  • .NET框架引用某些ASP.NET Core包显示被弃用
    原因:随着.NETCore3.0发布,许多ASP.NETCore程序集不再作为包发布到NuGet。而是改为将这些程序集包含在通过.NETCoreSDK和运行时安装程序安装的 Microsoft.AspNetCore.App 共享框架中。自.NETCore3.0起,使用 Microsoft.NET.Sdk.Web MSBuildSDK的项目隐式引用......
  • SOMEIPSRV_SD_MESSAGE_17: 订阅事件组否定确认条目类型
    测试目的:验证当SubscribeEventgroup请求中的实例ID未知时,DUT能否正确发送SubscribeEventgroupNegativeAcknowledgment消息。描述本测试用例旨在检查DUT在接收到包含未知实例ID的SubscribeEventgroup请求时,是否能够返回一个带有正确字段值的SubscribeEventgroupNeg......
  • C# 任意类型数据转JSON格式
    1publicclassObjectToJson2{3///<summary>4///List转成json5///</summary>6///<typeparamname="T"></typeparam>7///<paramname="jso......
  • 你不知道的JavaScript---强制类型转换
    你好,我是小白Coding日志,一个热爱技术的程序员。在这里,我分享自己在编程和技术世界中的学习心得和体会。希望我的文章能够给你带来一些灵感和帮助。欢迎来到我的博客,一起在技术的世界里探索前行吧!JavaScript是一种动态类型语言,这意味着变量可以在不同类型之间自由转换。在开发......
  • C++11平凡可复制类型检测is_trivially_copyable
    1.C++基础回顾     在C++11中,平凡类型(TrivialType)、平凡可复制类型(TrivialCopyable)、标准布局类型(Standard-layoutType)是描述类在内存中布局特性的术语,它们与类的构造、拷贝、赋值和销毁行为有关,也影响着类的内存布局和对齐方式。下面用通俗的语言解释这些概念:1.1.平......