关于String为值类型还是引用类型的讨论一直没有平息,最近一直在研究性能方面的问题,今天再次将此问题进行一次明确。希望能给大家带来点帮助,如果有错误请指出。

 来看下面例子:

 //值类型
 int a = 1;
 int b = a;
 a = 2;
 Console.WriteLine("a is {0},b is {1}", a, b);

 //字符串
 String str1 = "ab";
 String str2 = str1;
 str1 = "abc";
 Console.WriteLine("str1 is {0},str2 is {1}", str1, str2);
 Console.Read();

 根据上面的例子:你觉得输出结果应该是什么?

 输出结果:
 //a is 2,b is 1
 //str1 is abc,str2 is ab
 str2依然是ab,并没有随str1的改变而改变。

 如果String是引用类型,按理Str1和Str指针都指向同一内存地址,如果Str的内容发生改变,Str1应该也会相应变化。

 此例子,看着String更像是值类型,但是MSDN却说String是引用类型。

 引用类型包括:
 String
 所有数组(即使其元素是值类型)
 类类型(如Form)
 委托

 查看具体引用是否相同,如果Net能够查看内存地址就容易了,但不允许,只能通过间接方法来实现,看下面:

static void TestRefAddress()
{
String str1 = "abc";
String str2 = "abc";
int a = ;
int b = ;
StringBuilder strb1 = new StringBuilder("abc");
StringBuilder strb2 = new StringBuilder("abc");
Console.WriteLine("Reference equal for string: " + Object.ReferenceEquals(str1, str2)); //结果true
Console.WriteLine("Reference equal for int: " + Object.ReferenceEquals(a, b)); //结果false
Console.WriteLine("Reference equal for StringBuilder: " + Object.ReferenceEquals(strb1, strb2)); //结果false
Console.WriteLine("Value equal for string: " + str1.Equals(str2)); //结果true,类似于值类型
Console.Read();
}

 结果为何出现如此情况,分析如下:

 Console.WriteLine("Reference equal for string: " + Object.ReferenceEquals(str1, str2)); //结果true,不同对象,但引用地址相同
 Console.WriteLine("Reference equal for int: " + Object.ReferenceEquals(a, b)); //结果false,值类型装箱操作造成
 Console.WriteLine("Reference equal for StringBuilder: " + Object.ReferenceEquals(strb1, strb2)); //结果false,不同对象,引用地址不同
 Console.WriteLine("Value equal for string: " + str1.Equals(str2)); //结果true,类似于值类型

由第一条结果,可以判定不同的String的,相同的值,其引用地址相同,再由第四条结果,str1.Equals(str2),两者结合,可得出结论,两个String,如果赋值为同一个值,在内存中只有一个字符串存在,两个引用的地址相同。由此引出String的不变性。

String的不变性:

String最为显著的一个特点就是它具有恒定不变性。我们一旦创建了一个String,在managed heap 上为他分配了一块连续的内存空间,我们将不能以任何方式对这个String进行修改使之变长、变短、改变格式。所有对这个String进行各项操作(比如调用ToUpper获得大写格式的String)而返回的String,实际上另一个重新创建的String,其本身并不会产生任何变化。

    String 对象称为不可变的(只读),因为一旦创建了该对象,就不能修改该对象的值。有的时候看来似乎修改了,实际是String经过了特殊处理,每次改变值时都会建立一个新的String对象,变量会指向这个新的对象,而原来的还是指向原来的对象,所以不会改变。这也是String效率低下的原因。

String的不变,并非说String不能改变,而是其值不能改变。

在例子中str1="ab",这时在内存中就将“ab”存下来,如果再创建字符串对象,其值也等于“ab”,str2="ab",则并非再重新分配内存空间,而是将之前保存的“ab”的地址赋给str2的引用,这就能印证例子2中的结果。而当str1="abc"其值发生改变时,这时检查内存,发现不存在此字符串,则重新分配内存空间,存储“abc”,并将其地址赋给str1,而str2依然指向“ab”的地址,可以印证例子1中的结果。

结论:
    String是引用类型,只是编译器对其做了特殊处理。

转载来源:https://www.cnblogs.com/littlewrong/p/9927154.html

转:C# String为值类型还是引用类型的更多相关文章

  1. String为值类型还是引用类型

    关于String为值类型还是引用类型的讨论一直没有平息,最近一直在研究性能方面的问题,今天再次将此问题进行一次明确.希望能给大家带来点帮助. 如果有错误请指出. 来看下面例子: //值类型 int a ...

  2. string 是值类型,还是引用类型(.net)[转]

    转自http://hi.baidu.com/newfzks/item/b805f0f4edb0810dd89e7290 string 是值类型,还是引用类型(.net) 一. string 类型的用法 ...

  3. C# 值类型和引用类型

    一.基本概念 C#只有两种数据类型:值类型和引用类型 值类型在线程栈分配空间,引用类型在托管堆分配空间 值类型转为引用类型称成为装箱,引用类型转为值类型称为拆箱 以下是值类型和引用类型对照表 从上图可 ...

  4. 值类型与引用类型(特殊的string) Typeof和GetType() 静态和非静态使用 参数传递 相关知识

    学习大神博客链接: http://www.cnblogs.com/zhili/category/421637.html 一 值类型与引用类型 需要注意的string 是特殊类型的引用类型. 使用方法: ...

  5. 【译】.NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱

    为何要翻译 一来是为了感受国外优秀技术社区知名博主的高质量文章,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...

  6. 图解C#的值类型,引用类型,栈,堆,ref,out

    C# 的类型系统可分为两种类型,一是值类型,一是引用类型,这个每个C#程序员都了解.还有托管堆,栈,ref,out等等概念也是每个C#程序员都会接触到的概念,也是C#程序员面试经常考到的知识,随便搜搜 ...

  7. JAVA初学(1):值类型和引用类型的区别

    JAVA值类型和引用类型的区别(转)                                                          [定义] 引用类型表示你操作的数据是同一个,也就 ...

  8. .NET面试题解析(01)-值类型与引用类型

      系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 常见面试题目: 1. 值类型和引用类型的区别? 2. 结构和类的区别? 3. delegate是引用类型还 ...

  9. Emit学习(2) - IL - 值类型和引用类型(补)

    上周末回家去享受生活了, 工作是为了更好的生活嘛, 所以我把生活, 工作分的比较开. 这几天不是很忙, 在学习工作技能的同时, 发点博文, 也算是做一个学习笔记 上篇中, 贴出的地址里面那位哥, 也有 ...

随机推荐

  1. 管程(Moniter): 并发编程的基本心法

    JavaStorm 关注公众号获取更多并发 在吃透 Syncchronized 原理 中介绍了关于 Synchronize的实现原理,无论是同步方法还是同步代码块,无论是ACC_SYNCHRONIZE ...

  2. Wonder发布v1.1正式版本,新增资产预览、脚本、AssetBundle等

    更新说明 本次版本重点增加了脚本组件,并且实现了类似于unity的AssetBundle,支持动态加载场景和资源. 相关链接 官网 Wonder官方QQ群: 106047770 相关资料 Wonder ...

  3. 在CentOS 7 上使用Docker 运行.NetCore项目

    安装Docker CentOS 7 安装 Docker 编写Dockerfile 右键项目->添加->Docker 支持 选择Linux 修改为如下: FROM mcr.microsoft ...

  4. 在Mac上Python多版本切换

    1.安装Homebrewhttps://brew.sh/index_zh-cn.html 2.通过brew安装pyenv1)命令行输入:$ brew install pyenv(如果一直卡在Updat ...

  5. 办公达人私藏的EXCEL辅助工具,一人抵十人,高效办公就靠它了!

    有很多小伙伴在日常工作中都离不开EXCEL的使用,但EXCEL实在是有太多困难.又复杂的操作,时间紧任务重这一天又废柴了,哎! 别担心,今天将为您分享个逆天强大的EXCEL辅助工具,帮大家快速搞定—— ...

  6. PyQt5内嵌浏览器

    import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from P ...

  7. javascript学习总结之函数

    前言 在学习javascript函数的时候,有几个经常很容易混淆的方法,call,apply,bind,caller,callee,这些方法的使用,这些也可以说是会频繁使用的一些方法,在此通过查阅相关 ...

  8. Python类中的self的作用

    Python编写类的时候,每个函数第一个参数都是self.后来对Python越来越熟悉,再回头看self的概念,慢慢就明白了. 谷歌上有一段解释很到位,贴出来给大家: self represents ...

  9. java bean 属性验证框架 valid

    项目介绍 java 开发中,参数校验是非常常见的需求. 但是 hibernate-validator 在使用过程中,依然会存在一些问题. 特性 支持 fluent-validation 支持 jsr- ...

  10. 【CF528D】Fuzzy Search

    Problem Description 你有一个长度为 \(n\) 的串 \(S\),以及长度为 \(m\) 的串 \(T\). 现给定一个数 \(k\) ,我们说 \(T\) 在 \(S\) 的位置 ...