不可变到底是什么意思——也就是说,对象可变或不可变的结果是什么?特别是,为什么Java的字符串是不可变的?
我的理解是StringBuilder类型类似于String的可变等价。什么时候我会使用StringBuilder而不是字符串,反之亦然?
不可变到底是什么意思——也就是说,对象可变或不可变的结果是什么?特别是,为什么Java的字符串是不可变的?
我的理解是StringBuilder类型类似于String的可变等价。什么时候我会使用StringBuilder而不是字符串,反之亦然?
当前回答
实际上,如果你使用上面建议的维基百科定义,String不是不可变的。
字符串的状态改变后构造。看一下hashcode()方法。String将hashcode值缓存在本地字段中,但直到第一次调用hashcode()才计算它。这种对hashcode的惰性求值将String置于一个有趣的位置,作为状态发生变化的不可变对象,但如果不使用反射,就无法观察到它发生了变化。
所以也许不可变的定义应该是一个不能被观察到已经改变的对象。
如果一个不可变对象在创建后状态发生了变化,但是没有人可以看到它(没有反射),这个对象仍然是不可变的吗?
其他回答
因为公认的答案不能回答所有的问题。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
不可改变的意思是不可改变的。字符串对象一旦创建,其数据或状态就不能更改
考虑下面的例子:
class Testimmutablestring{
public static void main(String args[]){
String s="Future";
s.concat(" World");//concat() method appends the string at the end
System.out.println(s);//will print Future because strings are immutable objects
}
}
让我们考虑一下波纹图,
在这个图中,你可以看到一个新对象被创建为“Future World”。但不改变“未来”。因为字符串是不可变的。s,仍指“未来”。如果你需要给“未来世界”打电话,
String s="Future";
s=s.concat(" World");
System.out.println(s);//print Future World
为什么在java中字符串对象是不可变的?
因为Java使用了字符串字面量的概念。假设有5个引用变量,都指向一个对象“Future”。如果一个引用变量改变了对象的值,它将影响到所有的引用变量。这就是为什么字符串对象在java中是不可变的。
不可变的对象在创建后不能改变其状态。
尽可能使用不可变对象有三个主要原因,所有这些都将有助于减少你在代码中引入的错误数量:
It is much easier to reason about how your program works when you know that an object's state cannot be changed by another method Immutable objects are automatically thread safe (assuming they are published safely) so will never be the cause of those hard-to-pin-down multithreading bugs Immutable objects will always have the same Hash code, so they can be used as the keys in a HashMap (or similar). If the hash code of an element in a hash table was to change, the table entry would then effectively be lost, since attempts to find it in the table would end up looking in the wrong place. This is the main reason that String objects are immutable - they are frequently used as HashMap keys.
当你知道一个对象的状态是不可变的时,你还可以在代码中做一些其他的优化——例如缓存计算的哈希——但这些都是优化,因此没有那么有趣。
“不可变”意味着你不能改变值。如果你有一个String类的实例,你调用的任何方法,只要看起来是在修改这个值,实际上都会创建另一个String。
String foo = "Hello";
foo.substring(3);
<-- foo here still has the same value "Hello"
要保存更改,您应该这样做 Foo = Foo .sustring(3);
当您使用集合时,不可变与可变可能会很有趣。想想如果使用可变对象作为map的键,然后更改值会发生什么(提示:考虑equals和hashCode)。
不可变对象是不能通过编程改变的对象。它们特别适用于多线程环境或其他多个进程能够更改(突变)对象中的值的环境。
不过,澄清一下,StringBuilder实际上是一个可变对象,而不是不可变对象。常规的java String是不可变的(意味着一旦创建了它,就不能在不改变对象的情况下更改底层字符串)。
例如,假设我有一个名为ColoredString的类,它有一个String值和一个String颜色:
public class ColoredString {
private String color;
private String string;
public ColoredString(String color, String string) {
this.color = color;
this.string = string;
}
public String getColor() { return this.color; }
public String getString() { return this.string; }
public void setColor(String newColor) {
this.color = newColor;
}
}
在这个例子中,ColoredString被认为是可变的,因为您可以在不创建新的ColoredString类的情况下更改(突变)它的一个关键属性。这可能很糟糕的原因是,例如,假设您有一个GUI应用程序,它有多个线程,并且您正在使用ColoredStrings将数据打印到窗口。如果你有一个ColoredString的实例,它被创建为
new ColoredString("Blue", "This is a blue string!");
然后你会期望字符串总是“Blue”。然而,如果另一个线程获得了这个实例并调用
blueString.setColor("Red");
当你想要一个“蓝色”的字符串时,你会突然,很可能出乎意料地得到一个“红色”的字符串。正因为如此,在传递对象实例时,几乎总是首选不可变对象。在确实需要可变对象的情况下,通常只需从特定的控制字段传递副本来保护对象。
概括一下,在Java中,Java .lang. string是一个不可变对象(一旦创建就不能更改),而Java .lang. stringbuilder是一个可变对象,因为它可以在不创建新实例的情况下进行更改。