原文链接:https://www.cnblogs.com/huameitang/p/10528646.html

字符串是用于表示文本的字符的有序集合。 String对象是对象的有序集合 System.Char ,表示字符串; System.Char 对象对应于 utf-16 代码单元。 对象的值 String 是对象的顺序集合的内容 System.Char ,并且该值是不可变的 (也就是说,它是只读,反射也不能修改) 。 有关字符串不可变性的详细信息,请参阅 永久性和 StringBuilder 类 部分。 内存中对象的最大大小 String 为 2 GB,即约1000000000个字符。

string字符串的两大特性:

1、String不可变性:这个特性就是值类型的特性,所以在string操作上(赋值、拼接 、作参数)感觉就是值类型。

2、 拘留池(intern pool)的机制:是为了避免分配大量的字符串对象造成的过多的内存空间浪费。

.NET 的 CLR 运行时会在运行期间管理一个字符拘留池(string intern pool),在字符串拘留池中的字符串只有一个实例。

程序中会存在大量的字符串对象,如果每次都创建一个字符串对象,会比较浪费内存、性能低,因此CLR做了“暂存池”(拘留池,缓冲池,暂存池),在一些情况下对于字符串对象进行了重用。

例如,在下面的代码中,变量 abc 都是同一个实例:

var a = "walterlv";
var b = "walterlv";
var c = "walterlv";

把字符串输入拘留池和从暂存池中获取字符串

String.Intern:把字符串输入拘留池

String.Intern(x),将X添加到字符串池中,如果这个字符串已经存在池中,就返回这个存在的引用;如果不存在就将它加入到池中,并返回引用。

String.ISInterned(str):从暂存池中获取字符串

using System.Reflection;
using System.Text; string str1 = string.IsInterned("ddkkkkd");//会被存入拘留池
String str2 = new StringBuilder().Append("wx").Append("yz").ToString();
if ( str1 == null) Console.WriteLine("f");
if (string.IsInterned(str2) == null) Console.WriteLine("str2 is not Intern");
Console.WriteLine(string.IsInterned("ddkkkkd"));

String.IsInterned(str)要在暂存池中搜索的字符串,如果 str 在公共语言运行时的暂存池中,则返回对它的引用;否则返回 null

Console.WriteLine(object.ReferenceEquals("xyz", s));//编译器会把常量xyz ,加入池中
Console.WriteLine(object.ReferenceEquals("x" + "y" + "z", s));//编译器会把"x" + "y" + "z"当作常量xyz ,加入池中

不要池化

你可以在程序集中标记 CompilationRelaxations.NoStringInterning,这样,此程序集中的字符串就不会被池化。即便是在编译期间写下的字符串也会在运行时生成新的实例。

方法是在一个 C# 代码文件中添加特性标记。

[assembly: CompilationRelaxations(CompilationRelaxations.NoStringInterning)]

注意:不是所有的字符串都放在暂存池中,运行时期动态创建的字符串不会被加入到驻留池中。

关于字符串常量池的更深理解:

1. 驻留池由CLR来维护,其中的所有字符串对象的值都不相同。

2. 只有编译阶段的文本字符常量会被自动添加到驻留池。

3.运行时期动态创建的字符串不会被加入到驻留池中。

4.string.Intern()可以把动态创建的字符串加入到驻留池中。
5、林业耶夫总结:字符串内插生成的字符串 不会进入拘留池。

字符串虽然是引用类型,但是实即他更像值类型。

1)字符串的直接赋值:本身字符串就是引用类型,应该使用  new 对象方法一个实例,但是微软为了方便大家,可以直接定义字符串变量 并且赋值操作,例如: string a = "我的中国心"; ,这样只是简化我们的操作;

2)一个字符串赋值给另一个字符串变量:正常的引用类型会将两个引用变量指向同一个地址,但是一个字符串变量赋值给另一个字符串变量时,缺时建立了两个不同的地址空间,例如:

 string a = "12345"; string b = a;

上面的代码是两个不同的地址引用,只是把a的字符串内容赋值给b,a和b内容是一样的;

3)同一个字符串的多次赋值:按照一般的思维对一个字符串变量赋值,只是改变其内容,不会改变其地址,但是字符串比较奇葩,当给同一个字符串变量再次赋值的时候,它会重新分配内存空间,建立一个新的地址,然后把

这个地址赋值给原来的字符串变量,举例说明:

 string a= "123";  a = "456"
当第二次给a赋值为"456"时,它是创建新的内存空间,然后把新建的内存地址赋值给a变量,以前的"123"的内存摒弃不用,等待垃圾回收。

4)字符串作为函数参数传递:当字符串作为函数的参数传递时,本身是引用类型,应该是将变量的地址引用传递过去,以后在函数里对该参数的修改都会改变该字符串的值,但是我告诉你,结果它只是传递了该字符串的副本给

函数体,在函数里对该字符修改,居然不影响传递参数的值,当然,字符串的传递也可以当引用类型使用,主要添加ref 即可,可截图:

  5)字符串的比较:在字符串作为引用时,比较两个引用类型是否相等,只是比较两个引用的地址是否相等(除非你重载了Equal函数),但是当我们在比较字符串的时候,发现其实他们比较的是字符串的内容,并非是引用的地址,

这是引用string类重载了equal函数,是指比较字符的内容,在这点上  == 和 equal的结果其实是一样的;

6)字符串的内存驻留:当我们在创建具有相同的字符串内容的变量时,这些字符串变量其实指向的同一个内存地址,这点有点像C++里的内联;

 StringBuilder

StringBuilder的工作原理大致是这样的:

内部维护一个char[],并且有一个初始容量16。

新的字符串都加入到这个数组中。

当加入的字符超过容量时,就重新new一个更大的数组,并将原先的数组内容拷入新数组中。

将原有的数组进行垃圾回收,新的字符串加入到使用新的字符数组中。

StringBuilder的ToString方法见字符数组转换为一个String输出。

 StringBuilder与String互转

StringBuilder类是一个可变的字符序列。

StringBuilder()
构造一个不带任何字符的字符串生成器,其初始容量为 16 个字符。
StringBuilder(CharSequence seq)
构造一个字符串生成器,它包含与指定的 CharSequence 相同的字符。
StringBuilder(int capacity)
构造一个不带任何字符的字符串生成器,其初始容量由 capacity 参数指定。
StringBuilder(String str)
构造一个字符串生成器,并初始化为指定的字符串内容。 StringBuilder类的几个常用方法: append(任意类型) 追加到字符串后面 reverse 反转字符串 insert(int offset, 任意类型) 在某个index后插入字符串 toString() 返回String类的对象 先看一段String类的字符串拼接的代码。
String s = "hello" 会在常量池开辟一个内存空间来存储”hello"。

s += "world"会先在常量池开辟一个内存空间来存储“world"。然后再开辟一个内存空间来存储”helloworld“。

这么以来,001与002就成为了垃圾内存空间了。这么简单的一个操作就产生了两个垃圾内存空间,如果有大量的字符串拼接,将会造成极大的浪费。
StringBuilder的作用 上面的例子可以知道String类的字符串拼接会产生大量的垃圾内存空间。但是StringBuilder的字符串拼接是直接在原来的内存空间操作的,即直接在hello这个内存空间把hello拼接为helloworld。 来证明下: public class StringBuilderTest {
public static void main(String[] args){
StringBuilder sb = new StringBuilder();
StringBuilder sb2 = sb.append("hello");
System.out.println(sb);
System.out.println(sb2);
// 引用类型,判断的是他们的内存地址是否一样
System.out.println(sb == sb2);
}
} 输出结果是: hello
hello
true
String类与StringBuilder类的相互转换
1.String类转换为StringBuilder类 public class String12 {
public static void main(String[] args){
String s = "hello";
StringBuilder sb = new StringBuilder(s);
System.out.println(sb);
}
}
2.StringBuilder类转换为String类 public class String12 {
public static void main(String[] args){
StringBuilder sb = new StringBuilder();
sb.append("abc").append("efg");
String s = sb.toString();
System.out.println(s);
}
}

 string 和char之间的互操作

using IteratorTest;
using System.Reflection;
using System.Security.AccessControl; Console.WriteLine(); string name = "sfsfsfsdfsdfwertdhghk,u8rgdhf";
//字符串转成字符数组
char[] chars = name.ToCharArray(); //字符创当字符数组一样遍历
foreach (char c in name)
{
Console.WriteLine(c); } //3种方式 将字符数组转成字符串 Console.WriteLine(new string(chars));
Console.WriteLine(string.Concat(chars));
Span<char> span = new Span<char>(chars);
Console.WriteLine(span.ToString());

【C#】String| StringBuilder 字符的更多相关文章

  1. 深入源码剖析String,StringBuilder,StringBuffer

    [String,StringBuffer,StringBulider] 深入源码剖析String,StringBuilder,StringBuffer [作者:高瑞林] [博客地址]http://ww ...

  2. String, StringBuilder, StringBuffer问题

    1. 区别 String为字符串常量,而StringBuilder和StringBuffer都是字符串变量,其中StringBuilder线程非安全,StringBuffer线程安全. 每次对 Str ...

  3. String StringBuilder 包装类

    1. String 概述 程序中直接写上双引号的字符串就在字符串常量池中,new的不在池当中 java6之前常量池在方法区,java7以后将字符串常量池放在堆中 因为字符串是对象,应该在堆中 相同的字 ...

  4. difference among String,StringBuilder,StringBuffer

    difference among String,StringBuilder,StringBuffer String常用构造函数 String(byte[] bytes) String(byte[] b ...

  5. Java基础学习总结(65)——Java中的String,StringBuilder和StringBuffer比较

    字符串,就是一系列字符的集合. Java里面提供了String,StringBuffer和StringBuilder三个类来封装字符串,其中StringBuilder类是到jdk 1.5才新增的.字符 ...

  6. JDK源码分析系列---String,StringBuilder,StringBuffer

    JDK源码分析系列---String,StringBuilder,StringBuffer 1.String public final class String implements java.io. ...

  7. java中String StringBuilder StringBuffer比较和效率(性能)测试

    string stringbuilder stringbuffer三者的区别 从JDK源码看,String.StringBuilder.StringBuffer都是存放在char[] 数组字符串. 简 ...

  8. Android:认识R类、findViewById方法查找组件、@string查找字符、@color查找颜色、@drawable查找图片、@dimen某个组件尺寸定义、项目引入资源国际化

    导入 之前都是断断续续的看了一些于如何使用android开发的文章.资料等,到目前位置很多基础的东西都不清楚,于是去学习了别人的课程,才了认识了R类.findViewById方法查找组件.项目引入资源 ...

  9. String StringBuilder StringBuffer区别

    String StringBuilder StringBuffer String类是final类,不可以被继承,且它的成员方法也是final方法,当一个字符串对象进行操作操作时,任何的改变不会影响到这 ...

随机推荐

  1. 面渣逆袭:Java基础五十三问,快来看看有没有你不会的!

    大家好,我是老三, 面渣逆袭 系列继续.这节我们回到梦开始的地方--Java基础,其实过了萌新阶段,面试问基础就问的不多,但是保不齐突然问一下.想一下,总不能张口高并发.闭口分布式,结果什么是面向对象 ...

  2. 八数码问题(8-Puzzle Problem)

    八数码问题(8-Puzzle Problem) P1379 八数码难题 - 洛谷 题目概述:在 \(3 \times 3\) 的棋盘上摆放着 \(8\) 个棋子,棋子的编号分别为 \(1\) 到 \( ...

  3. linux中sed命令(全面解析)

    目录 一:linux中sed命令介绍 1.sed作用 2.sed命令格式 3.参数 4.sed的编辑模式 5.sed参数解析用法 二:sed 参数 -f 案例实战解析 1.前介 2.引入简介 3.方法 ...

  4. kubernetes之kubeadm 安装kubernetes 高可用集群

    1. 架构信息 系统版本:CentOS 7.6 内核:3.10.0-957.el7.x86_64 Kubernetes: v1.14.1 Docker-ce: 18.09.5 推荐硬件配置:4核8G ...

  5. MySQL的注释方法

    MySQL的三种注释方式 #1.单行注释 -- 2.单行注释(注意中间要带有一个空格才能生效) /*3.多行注释*/

  6. js trim()方法

    从字符串中移除前导空格.尾随空格和行终止符. 语法 stringObj.trim() 参数 stringObj 必选.String 对象或字符串.trim 方法不修改该字符串. 返回值 已移除前导空格 ...

  7. 连接docker里面的mysql失败解决

    场景:在虚拟机的docker容器中安装latest版本的mysql之后,在宿主机中使用navicat连接虚拟机中的mysql出现下图报错: 解决方法: 1.首先docker ps命令查看正在运行的容器 ...

  8. 关于LVS的问题总结

    关于LVS的问题总结 目录 关于LVS的问题总结 1. LVS工作模式及区别 2. LVS调度算法 3. LVS调度器你的常用算法(均衡策略) (1)固定调度算法:rr.wrr.dh.sh (2)动态 ...

  9. Java中File类的方法详解

    File类也是Java中一个比较重要的类,通过他我们可以实现对文件的一系列操作,其内置了很多方法,下面我将按方法的功能分块,逐一讲解: 快速导航 构造方法 常用方法 创建目录 判断 `is...` t ...

  10. 015 Linux 标准输入输出、重定向、管道和后台启动进程命令

    目录 1 三种标准输入输出 2 什么是重定向?如何重定向? (1)什么是重定向? (2)如何重定向? 3 管道符以及和它容易混淆的一些符号使用 (1)管道符 | (2)&和&& ...