.NET C# ‘string‘ 类型思考与解析

目录

  • .NET C# 'string' 类型思考与解析
    • 1 'string' 是值类型还是引用类型?
    • 2 为什么字符串要设计成引用类型,且相同字符串会用一个地址的字符串实例,这样解决了什么问题,有什么好处?

.NET C# ‘string’ 类型思考与解析

1 ‘string’ 是值类型还是引用类型?

首先,需要清楚什么是值类型,什么是引用类型?

值类型的特点包括:

  1. 分配在栈上。
  2. 变量直接包含数据。
  3. 赋值时进行的是数据的副本。
int i1 = 12;
int i2 = i1;
Console.WriteLine($"i1: {i1}, i2: {i2}");
i1 = 123;
Console.WriteLine($"i1修改后 - i1: {i1}, i2: {i2}");
Console.WriteLine();// 输出:
// i1: 12, i2: 12
// i1修改后 - i1: 123, i2: 12

引用类型的特点包括:

  1. 分配在托管堆上,而不是栈上。
  2. 变量存储的是对象的引用,而不是对象的实际数据。
  3. 通过垃圾回收机制来管理其生命周期。
TestClass t1 = new TestClass("test1");
TestClass t2 = t1;
Console.WriteLine($"t1: {t1.Id}, t2: {t2.Id}");
t1.Id = "test2";
Console.WriteLine($"t1修改后 - t1: {t1.Id}, t2: {t2.Id}");// 输出:
// t1: test1, t2: test1
// t1修改后 - t1: test2, t2: test2

值类型与引用类型赋值的区别:

  • 值类型赋值:将一个值类型变量赋值给另一个变量时,实际上是复制了该值的内容。这意味着两个变量各自拥有独立的数据副本,修改一个不会影响另一个。
  • 引用类型赋值:将一个引用类型变量赋值给另一个变量时,复制的是对象的引用,而不是对象本身的数据。这意味着两个变量引用的是同一个对象,修改这个对象会影响所有引用它的变量。

‘string’ 赋值的表现:

string s1 = "ab";
string s2 = s1;
Console.WriteLine($"s1: {s1}, s2: {s2}");
s1 = "abc";
Console.WriteLine($"s1赋值后 - s1: {s1}, s2: {s2}");// 输出:
// s1: ab, s2: ab
// s1赋值后 - s1: abc, s2: ab

尽管 string 是引用类型,但它的赋值行为看起来像值类型。这是因为字符串在 C# 中是不可变的。不可变性意味着字符串一旦创建,其内容就不能被改变。任何对字符串的修改操作都会创建一个新的字符串对象,而不是修改原有对象。这种设计使得字符串的赋值操作更加直观和安全。

在这个示例中,str2 最初被赋值为与 str1 相同的引用。但当 str2 被重新赋值为 "world" 时,str2 引用了一个新的字符串对象,而 str1 仍然引用原来的字符串对象 "hello"。这种行为看起来像值类型的赋值,但实际上是因为字符串的不可变性导致的。

深入理解字符串不可变性与驻留机制:

  1. 不可变性:不可变的设计使得每次修改字符串时都会生成一个新的字符串对象,而不会影响原有的字符串。这让字符串的赋值操作更像值类型的复制,而不是简单的引用复制。
  2. 字符串驻留:C# 运行时会对字符串进行驻留处理,也就是说,对于相同的字符串常量,运行时会确保它们引用同一个对象。这进一步提升了内存效率和性能。
string s3 = "asd";
string s4 = "asd";
string s5 = new string("asd");
Console.WriteLine($"s3: {s3}, s4: {s4}, ReferenceEquals: {object.ReferenceEquals(s3, s4)}");
Console.WriteLine($"s3: {s3}, s5: {s5}, ReferenceEquals: {object.ReferenceEquals(s3, s5)}");
// 输出:
// s3: asd, s4: asd, ReferenceEquals: True
// s3: asd, s5: asd, ReferenceEquals: False

最后看下C#源码中string的声明:

public sealed partial class String : IComparable, IEnumerable, IConvertible, IEnumerable<char>, IComparable<string?>, IEquatable<string?>, ICloneable

可以看出 ‘string’ 实际上是一个不可被继承的类。

2 为什么字符串要设计成引用类型,且相同字符串会用一个地址的字符串实例,这样解决了什么问题,有什么好处?

字符串被设计成引用类型且相同字符串实例共享同一个地址,主要是为了解决效率和资源管理的问题。具体来说,以下几个原因解释了这种设计决策:

  1. 内存使用效率
    • 在许多应用中,字符串是非常常用的数据类型。将字符串设计为引用类型可以避免在栈上频繁分配和释放内存,减轻栈内存的压力。
    • 字符串池(intern pool)的机制允许相同内容的字符串共享同一个内存地址,这减少了重复字符串实例的内存消耗。例如,如果有多个变量都存储相同的字符串内容,这些变量实际上会引用同一个字符串对象,从而节省内存。
  2. 性能优化
    • 字符串的不可变性(immutable)使得它们在多线程环境下是安全的,因为不会有多个线程同时修改同一个字符串对象,这避免了数据竞争和复杂的锁机制。
    • 因为字符串是不可变的,每次对字符串进行修改都会创建一个新的字符串对象。如果字符串是值类型,那么每次操作都需要复制整个字符串的内容,这会导致大量的性能开销。而引用类型则只是复制一个引用,效率更高。
  3. 字符拘留串池(intern pool)
    • .NET 框架使用字符拘留串池来优化相同字符串的存储。编译器和运行时会自动将相同的字符串文字(literal)放入字符串池中,从而保证内存中只有一份相同内容的字符串实例。这不仅节省了内存,而且提高了字符串比较操作的效率,因为可以通过比较引用来快速判断两个字符串是否相等。
    • 字符串池的机制也有助于在运行时减少垃圾回收的负担,因为较少的重复字符串对象需要被分配和回收。

综上所述,将字符串设计为引用类型,并允许相同字符串共享同一个实例,是为了在内存使用和性能上取得平衡,尤其是在处理大量字符串数据的情况下,这种设计带来了显著的效率提升。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/854429.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

现货白银实时交易平台的成长阶段 你出在哪个阶段?

很多人喜欢在现货白银平台上做模拟交易&#xff0c;因为他们认为现货白银实时交易平台上交易太痛苦了&#xff0c;不光随时会面临风险&#xff0c;而且还可能让自己出现大的亏损。如果投资者认为痛苦&#xff0c;那笔者觉得投资者不妨将在现货白银实时交易平台上做交易&#xf…

0 简单的图像分类

本文主要针对交通标识图片进行分类&#xff0c;包含62类&#xff0c;这个就是当前科大讯飞比赛&#xff0c;目前准确率在0.94左右&#xff0c;难点如下&#xff1a; 1 类别不均衡&#xff0c;有得种类图片2百多&#xff0c;有个只有10个不到&#xff1b; 2 像素大小不同&…

滑动窗口(LeeCode209题,以JS为例)

什么是滑动窗口&#xff1f; 滑动窗口是算法中一种非常有用的技术&#xff0c;特别是在处理数据序列或数组时。它的核心思想是维护一个固定大小的窗口&#xff0c;这个窗口在数据序列上滑动&#xff0c;以便于在窗口内的元素上进行操作或计算。滑动窗口技术通常用于解决与数据…

对 2024 年美赛选题的建议

对2024年美赛选题的建议包括&#xff1a; 1. 深入探讨当下全球面临的重大问题和挑战&#xff1a;鉴于美赛通常聚焦于全球性议题&#xff0c;如气候变化、可持续发展、数据分析等&#xff0c;参赛学生应关注这些议题&#xff0c;并深入研究相关数据与背景信息&#xff0c;以提出…

趋势Deep Security(Trend Micro Deep Security)安装

趋势Deep Security安装 Deep Security下载地址&#xff1a;https://help.deepsecurity.trendmicro.com/software.html?regsen-hk&prodid1716&_ga2.165737150.1637045249.1717402661-819692893.1716530462 前言 Trend Micro Deep Security是一个提供深度包检查、入侵…

单片机建立自己的库文件(4)

文章目录 前言一、新建自己的外设文件夹1.新建外设文件夹&#xff0c;做项目好项目文件管理2.将之前写的.c .h 文件添加到文件夹中 二、在软件中添加项目 .c文件2.1 编译工程保证没问题2. 修改项目列表下的名称 三、在软件项目中添加 .h文件路径四、实际使用测试总结 前言 提示…

sheng的学习笔记-AI-集成学习(adaboost,bagging,随机森林)

ai目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 目录​​​​​​​ 集成学习 什么是集成学习 集成学习一般结构&#xff1a; 示意图 弱学习器 经典算法 Boosting 什么是boosting 方法图 AdaBoost 算法 AdaBoost示意图 流程解析&#xff1a; 错误分类率error…

太速科技-FMC213V3-基于FMC兼容1.8V IO的Full Camera Link 输入子卡

FMC213V3-基于FMC兼容1.8V IO的Full Camera Link 输入子卡 一、板卡概述 该板卡为了考虑兼容1.8V电平IO&#xff0c;适配Virtex7&#xff0c;Kintex Ultrascale&#xff0c;Virtex ultrasacle FPGA而特制&#xff0c;如果要兼容原来的3.3V 也可以修改硬件参数。板卡支持1路…

快速欧氏聚类与普通欧氏聚类比较

1、前言 文献《FEC: Fast Euclidean Clustering for Point Cloud Segmentation》介绍了一种快速欧氏聚类方法,大概原理可以参考如下图,具体原理可以参考参考文献。 2、时间效率比较:快速欧氏聚类VS普通欧氏聚类 网上搜集的快速欧式聚类,与自己手写的普通欧式聚类进行对比,…

HTTP协议简单介绍

一、HTTP协议是什么 1、HTTP协议是以TCP协议为基础的文本协议。 2、HTTP协议采用请求和响应的模式。 3、HTTP协议可以传输二进制文件、文本文件、图片等资源。 4、HTTP协议支持表单上传&#xff0c;文件上传&#xff0c;文件下载等功能。 二、HTTP协议的格式 (一)请求格式…

SLG火并6月:多强鼎立,增量用户发展成行业新题

SLG赛道进入到6月&#xff0c;《三国&#xff1a;谋定天下》、《野兽领主&#xff1a;新世界》、《无尽冬日》大量新品袭来搅动市场。 在这样的关口&#xff0c;占据SLG半壁江山的灵犀互娱《三国志战略版》先一步刊登出战报&#xff0c;宣布1亿SLG玩家已收归麾下。 但新的挑战…

Linux时间子系统6:NTP原理和Linux NTP校时机制

一、前言 上篇介绍了时间同步的基本概念和常见的时间同步协议NTP、PTP&#xff0c;本篇将详细介绍NTP的原理以及NTP在Linux上如何实现校时。 二、NTP原理介绍 1. 什么是NTP 网络时间协议&#xff08;英语&#xff1a;Network Time Protocol&#xff0c;缩写&#xff1a;NTP&a…

COVINS-G编译注意事项

install_files.sh 修改source devel/setup.bash 为 source devel/setup.zsh cv_bridge 为了防止和本机的noetic的cv_bridge冲突&#xff0c;需要放入一个旧版本的cv_bridge。 先编译好opencv3_catkin&#xff0c;然后添加cv_bridge,也就是下载vision_opencv的melodic分支到cov…

华为数通企业面试笔试实验题

1. 笔试题 1.1 实验拓扑 1.2 实验要求 公司A为小型销售公司,需要实现基本上网功能,蓝色部分为外网线,提供DHCP服务 DnsServer:114.114.114.114 帮助网管排查某一台计算机在某一台交换机的某个端口 2. 操作步骤 配置路由器相关的LAN侧接口IP地址 配置DHCP项,要求有PC1与PC2…

Java StringBuffer 和 StringBuilder 类的比较与应用

Java 中的 StringBuffer 和 StringBuilder 类都用于处理字符串&#xff0c;但它们在性能和线程安全性方面有所不同。StringBuffer 是线程安全的&#xff0c;适合多线程环境下的字符串操作&#xff1b;而 StringBuilder 则是非线程安全的&#xff0c;提供了更高的性能。本文将从…

大模型KV Cache节省神器MLA学习笔记(包含推理时的矩阵吸收分析)

首先&#xff0c;本文回顾了MHA的计算方式以及KV Cache的原理&#xff0c;然后深入到了DeepSeek V2的MLA的原理介绍&#xff0c;同时对MLA节省的KV Cache比例做了详细的计算解读。接着&#xff0c;带着对原理的理解理清了HuggingFace MLA的全部实现&#xff0c;每行代码都去对应…

软件改为开机自启动

1.按键 win R,输入“shell:startup”命令, 然后就可以打开启动目录了&#xff0c;如下&#xff1a; 2.然后&#xff0c;把要开机启动的程序的图标拖进去即可。 参考&#xff1a;开机启动项如何设置

JAVA面试(六)

缓存 MemcachedredisRedis常见数据类型和使用Redis缓存持久化RDB-快照AOF-追加文件 Redis数据过期机制惰性删除定期删除 Redis缓存淘汰策略&#xff08;8种&#xff09;算法LRU &#xff08;Least Recently Used&#xff09;&#xff1a;最近最少使用LFU&#xff08;Least Freq…

java类型转换(强制类型转换)底层转换原理,此篇带你理解清楚

介绍 Java 中的类型强制转换&#xff08;Type Casting&#xff09;可以分为基本类型&#xff08;primitive types&#xff09;的强制转换和引用类型&#xff08;reference types&#xff09;的强制转换。它们在底层的原理和实现有所不同。以下是对这两种类型强制转换的详细解释…

ElasticSearch聚合排序

聚合排序 根据之前的博客可知,ES对于聚合结果的默认排序规则有时并非是我们希望的。可以使用ES提供的sort子句进行自定义排序,有多种排序方式可供选择: 按照聚合后的文档计数的大小进行排序按照聚合后的某个指标进行排序按照每个组的名称进行排序1.1 按文档计数排序 在聚合排…