不可变到底是什么意思——也就是说,对象可变或不可变的结果是什么?特别是,为什么Java的字符串是不可变的?
我的理解是StringBuilder类型类似于String的可变等价。什么时候我会使用StringBuilder而不是字符串,反之亦然?
不可变到底是什么意思——也就是说,对象可变或不可变的结果是什么?特别是,为什么Java的字符串是不可变的?
我的理解是StringBuilder类型类似于String的可变等价。什么时候我会使用StringBuilder而不是字符串,反之亦然?
当前回答
因为公认的答案不能回答所有的问题。11年零6个月后,我不得不给出答案。
有人能解释一下什么是不可变吗?
希望你指的是不可变对象(因为我们可以考虑不可变引用)。
对象是不可变的:iff一旦创建,它们总是表示相同的值(没有任何改变值的方法)。
为什么字符串是不可变的?
尊重上面的定义,这可以通过查看Sting.java源代码来检查。
不可变对象的优点/缺点是什么? 不可变类型有:
更安全,远离虫子。 更容易理解。 而且更愿意改变。
为什么像StringBuilder这样的可变对象应该优先于String,反之亦然?
缩小问题为什么我们在编程中需要可变的StringBuilder ? 它的一个常见用途是将大量字符串连接在一起,就像这样:
String s = "";
for (int i = 0; i < n; ++i) {
s = s + n;
}
使用不可变字符串,这会产生大量临时拷贝——在构建最终字符串的过程中,字符串的第一个数字(“0”)实际上被复制n次,第二个数字被复制n-1次,依此类推。实际上,做所有这些复制需要花费O(n2)时间,尽管我们只连接了n个元素。
StringBuilder的设计目的是最小化这种复制。它使用了一个简单但巧妙的内部数据结构来避免任何复制,直到最后,当你使用toString()调用来请求最终的String时:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; ++i) {
sb.append(String.valueOf(n));
}
String s = sb.toString();
获得良好的性能是我们使用可变对象的原因之一。另一个是方便的共享:通过共享一个公共的可变数据结构,程序的两个部分可以更方便地通信。
更多信息请访问:https://web.mit.edu/6.005/www/fa15/classes/09-immutability/#useful_immutable_types
其他回答
因为公认的答案不能回答所有的问题。11年零6个月后,我不得不给出答案。
有人能解释一下什么是不可变吗?
希望你指的是不可变对象(因为我们可以考虑不可变引用)。
对象是不可变的:iff一旦创建,它们总是表示相同的值(没有任何改变值的方法)。
为什么字符串是不可变的?
尊重上面的定义,这可以通过查看Sting.java源代码来检查。
不可变对象的优点/缺点是什么? 不可变类型有:
更安全,远离虫子。 更容易理解。 而且更愿意改变。
为什么像StringBuilder这样的可变对象应该优先于String,反之亦然?
缩小问题为什么我们在编程中需要可变的StringBuilder ? 它的一个常见用途是将大量字符串连接在一起,就像这样:
String s = "";
for (int i = 0; i < n; ++i) {
s = s + n;
}
使用不可变字符串,这会产生大量临时拷贝——在构建最终字符串的过程中,字符串的第一个数字(“0”)实际上被复制n次,第二个数字被复制n-1次,依此类推。实际上,做所有这些复制需要花费O(n2)时间,尽管我们只连接了n个元素。
StringBuilder的设计目的是最小化这种复制。它使用了一个简单但巧妙的内部数据结构来避免任何复制,直到最后,当你使用toString()调用来请求最终的String时:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; ++i) {
sb.append(String.valueOf(n));
}
String s = sb.toString();
获得良好的性能是我们使用可变对象的原因之一。另一个是方便的共享:通过共享一个公共的可变数据结构,程序的两个部分可以更方便地通信。
更多信息请访问:https://web.mit.edu/6.005/www/fa15/classes/09-immutability/#useful_immutable_types
不可变对象
一个对象被认为是不可变的,如果它的状态在被构造后不能改变。对于创建简单、可靠的代码,最大程度地依赖于不可变对象是一种被广泛接受的合理策略。
不可变对象在并发应用程序中特别有用。由于它们不能改变状态,因此不会被线程干扰破坏或在不一致的状态下观察到。
程序员通常不愿意使用不可变对象,因为他们担心创建新对象的成本,而不是在适当的地方更新对象。对象创建的影响经常被高估,并且可以被一些与不可变对象相关的效率所抵消。这包括减少垃圾收集带来的开销,以及消除保护可变对象不受损坏所需的代码。
下面的子节采用一个实例是可变的类,并从中派生一个具有不可变实例的类。在这样做的过程中,他们给出了这种转换的一般规则,并演示了不可变对象的一些优点。
源
不可变意味着一旦一个对象的构造函数完成执行,该实例就不能被改变。
这很有用,因为这意味着你可以传递对对象的引用,而不用担心其他人会改变它的内容。特别是在处理并发性时,对于永不更改的对象不存在锁定问题
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写了一篇关于这个的博客文章。基本上,你可以拥有接口是不可变的对象,但在幕后实际可变的私有状态(因此不能在线程之间安全地共享)。
其中一个含义与值如何存储在计算机中有关,例如,对于一个。net字符串,它意味着内存中的字符串不能被更改,当你认为你正在更改它时,你实际上是在内存中创建了一个新的字符串,并将现有的变量(这只是一个指向其他地方的实际字符集合的指针)指向新的字符串。
“不可变”意味着你不能改变值。如果你有一个String类的实例,你调用的任何方法,只要看起来是在修改这个值,实际上都会创建另一个String。
String foo = "Hello";
foo.substring(3);
<-- foo here still has the same value "Hello"
要保存更改,您应该这样做 Foo = Foo .sustring(3);
当您使用集合时,不可变与可变可能会很有趣。想想如果使用可变对象作为map的键,然后更改值会发生什么(提示:考虑equals和hashCode)。