我知道不可变对象总是具有相同的状态,即它们实际创建的状态。它们的不变量由构造函数建立,并且由于它们的状态在构造后不会改变,因此这些不变量始终保持良好状态,这就是为什么它们可以安全地在多线程环境中发布。这一切都很好,但是由于我们生活在一个动态的世界中,程序的状态不断变化,如果我们通过不可变的对象来构造程序的状态,这些对象会给我们带来什么好处呢?
4 回答
“这些物品给我们带来了什么好处”您已经回答了这个问题。
关于您问题的“动态”部分,如果您需要“更改”一个不可变对象,您可以从旧对象创建一个新对象:
Immutable oldObj = new Immutable(...);
Immutable newObj = new Immutable(oldObj.property1, "a new value for property 2");
如果您发现您一直重复这样做,那么您可能需要使对象可变,并添加能够在并发环境中使用该对象所需的相关踩踏安全功能。
不可变对象允许您干净地将状态更改传达给不同的线程。
使用不可变对象来表示线程之间交换的消息是一种很好的做法。一旦这样的消息被发送,它的有效载荷就不能被改变,这可以防止许多与并发相关的错误。如果一个线程需要传达一些进一步的变化,它只会发送下一条消息。
Immutable objects
当您需要一些状态从不改变的静态对象时非常有用。最大的优势是不变性,对象语义和智能指针使对象所有权成为一个有争议的问题。隐含地,这也意味着存在并发时的确定性行为。
Java 已经定义了一些不可变类,例如String
Integer
.
另一个好处是它们总是具有“故障原子性”(Joshua Bloch 使用的一个术语):如果不可变对象抛出异常,它永远不会处于不良或不确定状态。
假设你有一个像国家代码这样的静态对象的全局缓存,你可以在这里申请Immutability
。
在这种情况下,使用 String 对象时,不可变对象非常有用:
public class A {
private volatile String currentName = "The First Name";
public String getCurrentName() {
// Fast: no synching or blocking! Can be called billions of times by
// billions of threads with no trouble.
// (Does need to be read from memory always because it's volatile.)
return currentName;
}
public whatever someMethod() {
... code ...
// Simple assignment in this case. Could involve synchronization
// and lots of calculations, but it's called a lot less than
// getCurrentName().
currentName = newName;
... code ...
}
}
public class B {
... in some method ...
A objA = something;
// Gets "name" fast despite a billion other threads doing the same thing.
String name = objA.getCurrentName();
// From this point on, String referenced by "name" won't change
// regardless of how many times A.currentName changes.
... code with frequent references to objA
}
这允许必须保持一致(如果不是精确最新)的复杂数据(或者甚至是简单数据,这种情况下)被更新并以非常快速和线程安全的方式交付给任何需要它的人。交付的数据可能很快就会过时,但它会在调用方法期间保持其值并保持一致。