不可变的意思是什么?
如果一个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对象分配给str
variables。 你只是不能改变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
在上面, lit1
和lit2
都是用相同的string文字构造的,所以它们指向相同的内存地址; lit1 == lit2
结果为true
,因为它们是完全相同的对象。
但是, cons
是使用类构造函数构造的。 尽pipe参数是相同的string常量,但构造函数为cons
分配新的内存,这意味着尽pipe包含相同的数据, cons
与lit1
和lit2
不是同一个对象。
当然,由于三个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如何处理所有的对象,这是通过引用。 意思是所有对象在被实例化后都是可变的 ,这意味着你可以添加一个新的方法和属性的对象。 这很重要,因为如果你想要一个对象是不可变的,对象在被实例化后不能改变。