不可变和有效不可变对象之间的区别?

这是Java Concurrency in Practice中的一句话

共享只读对象包括不可变和有效不可变对象。

不可变和有效不可变对象之间有什么区别?

不可扩展且其字段都是final且本身不可变的类的实例是不可变的。

由于其方法的细节而无法变异的类的实例实际上是不可变的。 例如:

 final class C { final boolean canChange; private int x; C(boolean canChange) { this.canChange = canChange; } public void setX(int newX) { if (canChange) { this.x = newX; } else { throw new IllegalStateException(); } } } 

C某些实例实际上是不可变的,有些则不是。

另一个例子是零长度数组。 它们实际上是不可变的,即使它们的包含类不可certificate是不可变的,因为它们中没有可以改变的元素。


Joe-E使用validation程序来certificate某些类只允许不可变实例。 任何标有Immutable标记接口的东西都会被检查,并且像String这样的String (因为它的char[]不会逃脱而实际上是不可变的)会被视为不可变的。

Joe-E:一个面向安全的Java子集说

由Joe-E库定义的Immutable接口由语言专门处理:Joe-E veri fi er检查实现此接口的每个对象是否(深度)不可变,如果不能自动生成,则会引发编译时错误VERI网络版。

这是我从谷歌搜索和发现这篇文章的理解。 一个有效不可变的对象是一个包含可以变异的字段的对象,但它不会让任何东西改变这些字段,因为它永远不会给你一个引用。 例如,假设您创建了一个包含ArrayList的类。 ArrayList是可变的,但是如果你的类总是返回ArrayList的副本,并且你的类中的其他所有东西都是不可变的,那么你的类已经变得有效不可变:没有办法改变你的类的实例的状态。

博客文章将此作为有效不可变类的示例:

 import java.awt.*; public class Line { private final Point start; private final Point end; public Line(final Point start, final Point end) { this.start = new Point(start); this.end = new Point(end); } public void draw() { //... } public Point getStart() { return new Point(start); } public Point getEnd() { return new Point(end); } } 

Point对象是可变的,但没关系,因为这个类没有给任何人直接引用它的 Point实例。 相反,它返回一个具有相同值的新实例。 这样,没有人可以改变Line类的状态。 这使得Line类有效地不可变。

那么这与一个真正不可改变的类有什么不同呢? 一个真正不可变的类具有也是不可变的字段。 让我们想象一下Line真的是不变的。 要做到这一点,我们还必须想象Point是不可变的。 做出这些假设, getStart()方法可以像这样编写:

 public Point getStart() { return start; } 

看看这个答案:

有效不可变和不可变有效不可变和不可变之间的区别在于,在第一种情况下,您仍然需要以安全的方式发布对象。 对于不需要的真正不可变对象。 所以真正的不可变对象是首选,因为它们更容易发布,我上面说的原因说明为什么你可能更喜欢不同步的发布。

https://stackoverflow.com/a/7887675/1007546

不可变对象完全封装了它们的内部状态,并且它们不允许在构造之后修改该状态(可能使用final等),因此它们在多个线程之间共享是安全的,因为从共享对象读取对多个线程无害。

有效的不可变对象可以在多个线程之间共享之前改变它们的状态,但是在它们被“发布”(即多个引用被赋予多个线程)之后,它们保护自己免于修改。

不可变对象阻止您使用有用的软件工程实践,如延迟初始化,因为为了延迟属性或字段,它们必须是可变的,违反了它们的无忧无虑的并发共享属性。 有效的不可变对象通过仔细地知道何时可以安全地修改其内部状态以及何时被禁止来放松这些约束以获得两种世界方法的最佳效果。