String是一个奇怪的引用类型

简介: 今天从两张诡异的编程图聊到了String的不可变性、内存分布, 延伸谈到了String不可变性的设计设计考量(有先射箭再画靶的嫌疑☺️)针对频繁修改的String如何做内存优化

开局两张图,内容全靠刷。


df7e016b8b9928349d6499287181afb7.png


bc53cf357f11fd484c3beb56bd0beaf0.png


马甲哥看到这样的现象,一开始还是有点懵逼。


这个例子,string是纯粹的引用类型,但是在函数传值时类似于值传递;我之前给前后示例的内存变化图吧:


7c5f07437f2aeb2b70975529e46355e9.png


根因就是大多数高级语言都把String设计成不可变的: 由一个字符串池管理字符串面值。


为什么被设计成不可变。


这个我还真的搜索了一下[1]


总结起来:


  1. string 被设计为不可变, 是因为 string在现代任何语言中,使用很频繁:多个对象可能都是这个字符面值, 然后就设计一个Pool来存储string。既然pool里面共享字符面值,修改的时候又不能影响到别人,那就只好重新拷贝产生新的字符面值。


  1. 不可变资源消除了多线程中的资源竞争:对于文本的修改都会导致创建新空间,因此在多个线程同时访问文本无需设置锁,这对高频使用的String很友好。


  1. 字符串不变性对于[在哈希表中使用字符串作为键]很友好,需要计算哈希值的对象必须是不可变的,以确保哈希值不变。


  • 一个有意思的现象是:String虽然是引用类型,字符串对比时却表现的像值类型


string str1="FooFoo";
string strFoo="Foo";
string str2= strFoo + strFoo;
return str1 == str2;           //  返回true


正因为String不可变性 & Pool的机制,频繁变更字符串,会在池中产生很多临时的不用的字符串,所以我们有了优化的套路:


StringBuilder


代表可变的字符串,一旦修改不会尝试创建新对象,而是动态扩展内存


var ss = new StringBuilder("Hello ", 100);  // 初次字符容量100
ss.Append("www.cnblogs.com");
Console.WriteLine(ss.ToString());  // ss打印结果为:222


c75d719a98f68eab826467aa17330147.png


Span


Span该出圈了,


Span提供对内存连续区域的类型安全访问,该内存可以位于堆、堆栈、甚至是非托管内存;


与String不可变性相关的是ReadOnlySpan(值类型), 提供内存数据的只读视图,每次切片不会产生新对象,而是在已存在的连续空间上创造新的视图。


var text = "https://www.cnblogs.com/JulianHuang/p/14817621.html";
ReadOnlySpan<char> nameSpan = text.AsSpan(8, 15);
nameSpan = nameSpan.Slice(4,7);
Console.WriteLine(nameSpan.ToString());



07a31e57c712f52e13e2dbcfb73cfcf0.png


总结输出


今天从两张诡异的编程图聊到了String的不可变性、内存分布, 延伸谈到了


  1. String不可变性的设计设计考量(有先射箭再画靶的嫌疑☺️)


  1. 针对频繁修改的String如何做内存优化
相关文章
|
存储 Java
基本类型、包装类型、引用类型、String等作为实参传递后值会不会改变?
基本类型、包装类型、String类型作为参数传递之后,在方法里面修改他们的值,原值不会改变!引用类型不一定,要看是怎么修改它的。
112 0
|
前端开发 JavaScript 索引
前端祖传三件套JavaScript的对象之常用引用类型的String
字符串是 JavaScript 中最常用的数据类型之一,作为 JavaScript 的基础之一,它拥有一系列的函数和方法,可以方便地完成各种字符串操作。在本文中,我们将深入探讨 JavaScript 字符串的对象类型,并介绍其中一些常用的引用类型。
90 0
C# string特殊引用类型
一、string的确是引用类型 常规上是这样定义的:     string是引用类型,但是其又具有值类型的一些特性。   static void Main(string[] args) ...
856 0
string 是值类型,还是引用类型(.net)
一. string 类型的用法比较像值类型 稍微有点.NET 编程知识的人都知道 string是引用类型。我为什么还有此一问?因为string的使用非常像值类型。举个例子: string str = "abc"; Test(str); MessageBox.Show(str); private void Test(string str) {      str = str + "de"; }   运行上面的代码你会发现 str始终是abc,这就有点像值类型。
977 0
|
2月前
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
38 0
java基础(13)String类
|
29天前
|
Java
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
本文深入探讨了Java中方法参数的传递机制,包括值传递和引用传递的区别,以及String类对象的不可变性。通过详细讲解和示例代码,帮助读者理解参数传递的内部原理,并掌握在实际编程中正确处理参数传递的方法。关键词:Java, 方法参数传递, 值传递, 引用传递, String不可变性。
50 1
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
|
26天前
|
安全 Java 测试技术
Java零基础-StringBuffer 类详解
【10月更文挑战第9天】Java零基础教学篇,手把手实践教学!
23 2
|
28天前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
19 1
|
1月前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
49 4

热门文章

最新文章