不可变到底是什么意思——也就是说,对象可变或不可变的结果是什么?特别是,为什么Java的字符串是不可变的?
我的理解是StringBuilder类型类似于String的可变等价。什么时候我会使用StringBuilder而不是字符串,反之亦然?
不可变到底是什么意思——也就是说,对象可变或不可变的结果是什么?特别是,为什么Java的字符串是不可变的?
我的理解是StringBuilder类型类似于String的可变等价。什么时候我会使用StringBuilder而不是字符串,反之亦然?
当前回答
不可变意味着一旦一个对象的构造函数完成执行,该实例就不能被改变。
这很有用,因为这意味着你可以传递对对象的引用,而不用担心其他人会改变它的内容。特别是在处理并发性时,对于永不更改的对象不存在锁定问题
e.g.
class Foo
{
private final String myvar;
public Foo(final String initialValue)
{
this.myvar = initialValue;
}
public String getValue()
{
return this.myvar;
}
}
Foo不必担心getValue()的调用者可能会更改字符串中的文本。
如果你想象一个类似于Foo的类,但是成员是StringBuilder而不是String,你可以看到getValue()的调用者能够改变Foo实例的StringBuilder属性。
还要注意你可能会发现的不同类型的不变性:Eric Lippert写了一篇关于这个的博客文章。基本上,你可以拥有接口是不可变的对象,但在幕后实际可变的私有状态(因此不能在线程之间安全地共享)。
其他回答
实际上,如果你使用上面建议的维基百科定义,String不是不可变的。
字符串的状态改变后构造。看一下hashcode()方法。String将hashcode值缓存在本地字段中,但直到第一次调用hashcode()才计算它。这种对hashcode的惰性求值将String置于一个有趣的位置,作为状态发生变化的不可变对象,但如果不使用反射,就无法观察到它发生了变化。
所以也许不可变的定义应该是一个不能被观察到已经改变的对象。
如果一个不可变对象在创建后状态发生了变化,但是没有人可以看到它(没有反射),这个对象仍然是不可变的吗?
不可变对象是指创建后不能修改的对象。一个典型的例子是字符串字面量。
越来越流行的D编程语言通过“不变”关键字具有“不变性”的概念。查看Dr.Dobb关于它的文章http://dobbscodetalk.com/index.php?option=com_myblog&show=Invariant-Strings.html&Itemid=29。它完美地解释了这个问题。
其中一个含义与值如何存储在计算机中有关,例如,对于一个。net字符串,它意味着内存中的字符串不能被更改,当你认为你正在更改它时,你实际上是在内存中创建了一个新的字符串,并将现有的变量(这只是一个指向其他地方的实际字符集合的指针)指向新的字符串。
String s1="Hi";
String s2=s1;
s1="Bye";
System.out.println(s2); //Hi (if String was mutable output would be: Bye)
System.out.println(s1); //Bye
s1="Hi":创建一个包含"Hi"值的对象s1。
S2 =s1:引用s1对象创建对象S2。
s1="Bye":之前的s1对象的值不会改变,因为s1有String类型,而String类型是一个不可变的类型,相反,编译器创建了一个新的String对象与"Bye"值和s1引用它。在这里,当我们打印s2值时,结果将是“Hi”而不是“Bye”,因为s2引用了前一个具有“Hi”值的s1对象。
不可变对象
一个对象被认为是不可变的,如果它的状态在被构造后不能改变。对于创建简单、可靠的代码,最大程度地依赖于不可变对象是一种被广泛接受的合理策略。
不可变对象在并发应用程序中特别有用。由于它们不能改变状态,因此不会被线程干扰破坏或在不一致的状态下观察到。
程序员通常不愿意使用不可变对象,因为他们担心创建新对象的成本,而不是在适当的地方更新对象。对象创建的影响经常被高估,并且可以被一些与不可变对象相关的效率所抵消。这包括减少垃圾收集带来的开销,以及消除保护可变对象不受损坏所需的代码。
下面的子节采用一个实例是可变的类,并从中派生一个具有不可变实例的类。在这样做的过程中,他们给出了这种转换的一般规则,并演示了不可变对象的一些优点。
源