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

来看下面例子:

  1. //值类型
    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();

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

输出结果:

  1. //结果:
    //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能够查看内存地址就容易了,但不允许,只能通过间接方法来实现,看下面:

  1. static void TestRefAddress()
    {
    String str1 = "abc";
    String str2 = "abc";
    int a = 1;
    int b = 1;
    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();
    }

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

  1. 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是引用类型,只是编译器对其做了特殊处理。

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

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

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

  2. 转:C# String为值类型还是引用类型

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

  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. JS数组根据属性来实现排序

    var data = [{ name: "zhao", age: }, { name: "qian", age: }, { name: "sun&qu ...

  2. javaScript 中String的常用方法

    1.length() 字符串的长度 例:char chars[]={'a','b'.'c'}; String s=new String(chars); int len=s.length(); 2.ch ...

  3. spring项目log4j使用入门

    log4j是Java开发中经常使用的一个日志框架,功能强大,配置灵活,基本上可以满足项目开发中对日志功能的大部分需求.我前后经历了四五个项目,采用的日志框架都是log4j,这也反应了log4j受欢迎的 ...

  4. CSS样式表初学,比C#和JS简单

    今天咱们一起来看下CSS样式表的基本基础 经常看博客或者喜欢钻研代码这一类的人对CSS可能有所耳闻,但具体的可能不是很清楚 那什么是CSS呢?与HTML又有什么区别呢?今天咱们就来说道下这个CSS C ...

  5. 纯css兼容个浏览器input[type='radio']不能自定义样式

    各个浏览器对于表单input[type='radio'].input[type='checkbox']的样式总是各有差异   //html <div class="remember-a ...

  6. 关于REST的浅显了解

    REST 是一种软件架构风格 1.定义 REST即表述性状态传递(Representational State Transfer) 是一组架构约束条件和原则.是设计风格而不是标准. 满足这些约束条件和 ...

  7. Android 如何本地加载pdf文件

    大部分app打开pdf文件是通过intent调起手机中能打开pdf文件的工具,来查看pdf文件,如果需求是,用户在app内下载好pdf文件后,不通过第三方的工具,本地打开. 这样的需求要怎么实现呢?上 ...

  8. (知识点)JavaScript闭包

    下面是我对闭包的理解:(把他们整理出来,整理的过程也是在梳理) 1.首先,在理解闭包之前: 我们首先应该清楚下作用域和作用域链 作用域:每个函数定义时创建时自己的环境即作用域 作用域链:函数内可访问自 ...

  9. PL/SQL 自动补全[转]

    1.新建 shortcuts.txt 内容如下: s = SELECT t.* FROM t w = WHERE b = BETWEEN AND l = LIKE '%%' o = ORDER BY ...

  10. undo表空间

    undo表空间undo表空间的管理,主要包括创建.删除.修改.切换.其中需要注意的是不能在undo表空间创建数据库对象,还有就是只能是单文件或大文件表空间. 创建创建主要有两种方法,一种是在创建数据库 ...