不可变的意思是什么?

如果一个string是不可变的,那么这是否意味着….(让我们假设JavaScript)

var str = 'foo'; alert(str.substr(1)); // oo alert(str); // foo 

这是否意味着,当调用一个string的方法时,它会返回修改的string,但它不会改变初始string?

如果string是可变的,这是否意味着第二个alert()将返回oo

这意味着一旦你实例化对象,你不能改变它的属性。 在你的第一个提醒你没有改变富。 你正在创build一个新的string。 这就是为什么在你的第二个提醒它会显示“foo”,而不是oo。

这是否意味着,当调用一个string的方法时,它会返回修改的string,但它不会改变初始string?

是。 一旦创build,任何东西都不能改变它。 现在这并不意味着你不能将一个新的string对象分配给strvariables。 你只是不能改变str引用的当前对象。

如果string是可变的,这是否意味着第二个alert()将返回oo?

技术上,不,因为substring方法返回一个新的string。 使对象可变,不会改变方法。 使其可变意味着在技术上,你可以这样做,使得子string将改变原来的string,而不是创build一个新的。

在较低的层次上,不变性意味着string存储的内存不会被修改。 一旦创build了string"foo" ,就会分配一些内存来存储值"foo" 。 这个记忆不会被改变。 如果用substr(1)修改string,会创build一个新的string,并分配一个不同的内存部分来存储"oo" 。 现在你在内存中有两个string"foo""oo" 。 即使你不再使用"foo" ,它仍然会坚持到垃圾被收集。

为什么string操作比较昂贵的一个原因。

不可变意味着不能改变或修改。

所以当你给一个string赋值时,这个值是从头开始创build的,而不是被replace。 所以每当一个新的值被分配给同一个string时,就会创build一个副本。 所以现实中,你永远不会改变原来的价值。

我对JavaScript没有把握,但在Java中,string通过“string常量池”(String Constant Pool)向不变性迈进了一步。 string可以用string( "foo" )或String类构造函数构造。 使用string文字构造的string是string常量池的一部分,相同的string文字将始终是来自池的相同内存地址。

例:

  String lit1 = "foo"; String lit2 = "foo"; String cons = new String("foo"); System.out.println(lit1 == lit2); // true System.out.println(lit1 == cons); // false System.out.println(lit1.equals(cons)); // true 

在上面, lit1lit2都是用相同的string文字构造的,所以它们指向相同的内存地址; lit1 == lit2结果为true ,因为它们是完全相同的对象。

但是, cons是使用类构造函数构造的。 尽pipe参数是相同的string常量,但构造函数为cons分配新的内存,这意味着尽pipe包含相同的数据, conslit1lit2不是同一个对象。

当然,由于三个string都包含相同的字符数据,所以使用equals方法将返回true。

(当然,这两种types的string结构都是不可变的)

不可变意味着价值不能改变。 一旦创build一个string对象不能被修改为它的不可变。 如果您请求string的子string,则创build具有所请求部分的新string。

在操纵string时使用StringBuffer代替使得操作效率更高,因为StringBuffer将string存储在字符数组中,并使用variables来保存字符数组的容量和数组的长度(string以char数组的forms)

从string到堆栈…从Eric Lippert的博客中摘取一个简单明了的例子:

在C#3.0中使用A *查找path,第二部分

像System.Collections.Generic.Stack这样的可变堆栈显然是不合适的。 我们希望能够采用现有的path并为其最后一个元素的所有邻居创build新path,但是将新节点推入标准堆栈会修改堆栈。 在推送之前,我们必须复制堆栈,这很愚蠢,因为那样我们会不必要地复制所有的内容。

不可变的堆栈没有这个问题。 推到一个不可改变的栈只是创build一个全新的栈,连接到旧的栈尾。 由于堆栈是不可变的,因此不会有其他代码出现,并且会尾随内容。 你可以继续使用旧的堆栈来满足你内心的需求。

要深入了解不可变性,请阅读Eric的post:

C#中的不变性第一部分:不变性的种类

可变性的教科书定义是有责任的或可以改变或改变的。 在编程中,我们使用这个词来表示其状态允许随时间变化的对象。 一个不可变的值是完全相反的 – 在它被创build之后,它永远不会改变。

如果这看起来很奇怪,请允许我提醒你,我们一直使用的许多价值实际上是不变的。

 var statement = "I am an immutable value"; var otherStr = statement.slice(8, 17); 

我想没有人会惊讶于第二行绝不会改变语句中的string。 事实上,没有任何string方法会改变它们所操作的string,它们都返回新的string。 原因是string是不可改变的 – 它们不能改变,我们只能制造新的string。

string不是JavaScript中内置的唯一不可变的值。 数字也是不可改变的。 你甚至可以想象一个评估expression式2 + 3改变数字2的含义的环境吗? 这听起来很荒唐,但我们一直都在用我们的对象和数组来做这件事。

掌握这个概念的一种方法是看看javascript如何处理所有的对象,这是通过引用。 意思是所有对象在被实例化后都是可变的 ,这意味着你可以添加一个新的方法和属性的对象。 这很重要,因为如果你想要一个对象是不可变的,对象在被实例化后不能改变。