不可变到底是什么意思——也就是说,对象可变或不可变的结果是什么?特别是,为什么Java的字符串是不可变的?
我的理解是StringBuilder类型类似于String的可变等价。什么时候我会使用StringBuilder而不是字符串,反之亦然?
不可变到底是什么意思——也就是说,对象可变或不可变的结果是什么?特别是,为什么Java的字符串是不可变的?
我的理解是StringBuilder类型类似于String的可变等价。什么时候我会使用StringBuilder而不是字符串,反之亦然?
当前回答
不可变对象是不能通过编程改变的对象。它们特别适用于多线程环境或其他多个进程能够更改(突变)对象中的值的环境。
不过,澄清一下,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是一个可变对象,因为它可以在不创建新实例的情况下进行更改。
其他回答
其中一个含义与值如何存储在计算机中有关,例如,对于一个。net字符串,它意味着内存中的字符串不能被更改,当你认为你正在更改它时,你实际上是在内存中创建了一个新的字符串,并将现有的变量(这只是一个指向其他地方的实际字符集合的指针)指向新的字符串。
java.time
这可能有点晚了,但为了理解什么是不可变对象,请考虑以下来自新的Java 8日期和时间API (Java . Time)的示例。你可能知道,Java 8中的所有日期对象都是不可变的,所以在下面的例子中
LocalDate date = LocalDate.of(2014, 3, 18);
date.plusYears(2);
System.out.println(date);
输出:
2014-03-18
这将打印与初始日期相同的年份,因为plusYears(2)返回一个新对象,因此旧日期仍然不变,因为它是一个不可变对象。一旦创建,您就不能进一步修改它,日期变量仍然指向它。
因此,该代码示例应该捕获并使用由plusYears调用实例化并返回的新对象。
LocalDate date = LocalDate.of(2014, 3, 18);
LocalDate dateAfterTwoYears = date.plusYears(2);
date.toString()…2014-03-18 dateAfterTwoYears.toString()…2016-03-18
一旦实例化,就不能更改。考虑一个类,它的实例可能用作哈希表或类似的键。查看Java最佳实践。
我真的很喜欢SCJP Sun认证程序员Java 5学习指南的解释。
为了提高Java的内存效率,JVM留出了一个特殊的内存区域,称为“字符串常量池”。当编译器遇到String字面值时,它会检查池,看看是否已经存在相同的String。如果找到匹配,则对新字面值的引用将指向现有的String,并且不会创建新的String字面值对象。
不可变对象
一个对象被认为是不可变的,如果它的状态在被构造后不能改变。对于创建简单、可靠的代码,最大程度地依赖于不可变对象是一种被广泛接受的合理策略。
不可变对象在并发应用程序中特别有用。由于它们不能改变状态,因此不会被线程干扰破坏或在不一致的状态下观察到。
程序员通常不愿意使用不可变对象,因为他们担心创建新对象的成本,而不是在适当的地方更新对象。对象创建的影响经常被高估,并且可以被一些与不可变对象相关的效率所抵消。这包括减少垃圾收集带来的开销,以及消除保护可变对象不受损坏所需的代码。
下面的子节采用一个实例是可变的类,并从中派生一个具有不可变实例的类。在这样做的过程中,他们给出了这种转换的一般规则,并演示了不可变对象的一些优点。
源