资讯专栏INFORMATION COLUMN

字符串的不变性

zhaochunqi / 2010人阅读

摘要:不少语言对字符串的实现,都采用了限定不变性。字符串的不可变性有不少好处,但是如果程序员忘了这一点也会导致问题。所以字符串不可变就是存储的代价。另一个场景是字符串可以用于哈希表的键,而键是不可以改变值的。

像是js,以及c#等一系列的语言,推出任何一个特征都要和c比一比,你知道的:)。

string的不可变性也是一样,你看:

C的string是可以改变的。
你可以

char str[] = "Foo";
str[0] = ‘G"

str的内容确实被改变了。可以通过print来证明。打印内容,也打印指针。指针不变,内容变了。

2.js的不可改.如下的代码,没有任何效果,也可以log出来证明
var str = "foo";
str[0] = "g" ;

因为,语义上来说,这样做意味着原位修改str的内存区内容

但是你可以
var str = "foo";
var = "bar"

因为原位置的内存没有修改,是新分配的。只是打印不了指针,不好直接证明。要么就看代码,那就啰嗦了。非常非常的啰嗦。

不少语言对字符串的实现,都采用了限定不变性。不能说这是不费解的:为何去创建一个新字符串,而不是去修改它呢?毕竟c就是这样做的。

字符串的不可变性有不少好处,但是如果程序员忘了这一点也会导致问题。

如下的c#代码会创建10000个字符串对象,但是除了最后一个,后面都是垃圾需要被回收的。

string s = string.Empty;

for (int i = 0; i < 10000; i++)
{
    s += "x";
}

通过cld profiler可以看到这张图。

这样的场景应该使用StringBuilder。而不是字符串连接。

StringBuilder sb =  StringBuilder();
for( i = ; i < 10000; i++)
{
    sb.Append();
}
string x = sb.ToString();

针对js,也可以自己做一个StringBuilder

function StringBuilder() {
    this._array = [];
    this._index = 0;
}

StringBuilder.prototype.append = function (str) {
    this._array[this._index] = str;
    this._index++;
}

StringBuilder.prototype.toString = function () {
    return this._array.join("");
}

为何设计者决定实现不可变字符串呢?

这个和存储优化有关。字符串都存储在俘虏池(intern pool)内,因为string都在intern pool内,所以,相同的字符串引用一致。这样的存储效果很好。

可是,如果允许修改string,那么a修改了,b也会跟着修改,d也是。可是,语义上来说,我们认为他们是不同的变量,不应该联动。所以字符串不可变就是intern pool存储的代价。

string a = "xx";
string b = "xx";
string c = "x";
string d = String.Intern(c + c);
Console.WriteLine((object)a == (object)b); Console.WriteLine((object)a == (object)d);

String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,c# 查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;

不变性,对多线程应用是有好处的。
另一个场景是字符串可以用于哈希表的键,而键是不可以改变值的。

string key = "abc";
Hashtable ht = new Hashtable();
ht.Add(key, 123);

key = "xbc";

Console.WriteLine(key); // xbc
Console.WriteLine(ht["abc"]); // 123

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85554.html

相关文章

  • [译]JavaScript中的不变性(Immutability)

    摘要:整个这个雷区面板都是由的和组成的,最后由的方法对其进行不可变化处理剩下的主要逻辑部分就是扫雷了,传入扫雷游戏对象一个不可变结构做为第一个参数,以及要扫的那个雷区块对象,最后返回新的扫雷游戏实例。 不可变性(Immutability)是函数式编程的核心原则,在面向对象编程里也有大量应用。在这篇文章里,我会给大家秀一下到底什么是不可变性(Immutability)、她为什么还这么屌、以及在...

    clasnake 评论0 收藏0
  • 第3章:抽象数据类型(ADT)和面向对象编程(OOP) 3.1数据类型和类型检查

    摘要:所有变量的类型在编译时已知在程序运行之前,因此编译器也可以推导出所有表达式的类型。像变量的类型一样,这些声明是重要的文档,对代码读者很有用,并由编译器进行静态检查。对象类型的值对象类型的值是由其类型标记的圆。 大纲 1.编程语言中的数据类型2.静态与动态数据类型3.类型检查4.易变性和不变性5.快照图6.复杂的数据类型:数组和集合7.有用的不可变类型8.空引用9.总结 编程语言中的数据...

    zhangqh 评论0 收藏0
  • String 的不变性

    摘要:的不变性,如下图所示,当你改变了的之后指向了一个新的对象原对象不做改变。但其引用的数组是可变的。所以的不可变性的关键并不是的作用。同时编写者为了避免因为的不可变性导致占用大量空间,为此设计了字符串常量池 在猫眼的面试中被面试官问到为什么String的字符串是不变的。当时我的回答是因为String类是用final关键字修饰的,当被问到为什么用 final修饰就是不可变的时候我发现自己说的...

    sydMobile 评论0 收藏0
  • Java的String不可变性

    摘要:但是通过构造函数的并不是。通过构造函数创建的变量在机制上与其他对象一致,都是在上创建新的对象,然后把引用赋给变量。此外,的方法和等方法实现均是调用了构造函数创建了新的对象,所以他们返回的也都是存在于上的新对象。 String经常在一个语言中或多或少都有些特殊地位。在Java亦不例外。今天先来讨论,String是不可变的。 String是引用类型,String变量储存一个地址,地址指向内...

    atinosun 评论0 收藏0
  • 翻译连载 | JavaScript轻量级函数式编程-第6章:值的不变性 |《你不知道的JS》姊妹篇

    摘要:但在开始之前应该心中有数值的不可变性并不是说我们不能在程序编写时不改变某个值。这些都是对值的不可变这个概念的误解。程序的其他部分不会影响的赋值。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTML 最坚实的梁柱;分享,是 CSS 里最闪...

    ysl_unh 评论0 收藏0

发表评论

0条评论

zhaochunqi

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<