Java不可变对象

tmg*_*mgr 6 java string object immutability wrapper

我正在学习不变性的概念.

我知道一旦创建对象,不可变对象就无法更改它们的值.

但我不明白以下对不可变对象的使用.

他们是

  • 是自动线程安全的,没有同步问题. How ? Proof ?
  • 不需要复制构造函数. How ? Any example ?
  • 不需要克隆的实现 How ? Any example ?
  • 当用作场时,不需要防御性地复制 How ? Any example ?
  • 总是有"failure atomicity" (a term used by Joshua Bloch):如果一个不可变对象抛出异常,它永远不会处于不受欢迎或不确定的状态.How ? Any example ?

有人可以通过支持它的例子详细解释这些要点吗?

谢谢.

Nic*_*ole 10

..自动线程安全,没有同步问题

当两个不同的线程修改同一对象的状态时,会发生并发问题.不可变对象无法修改,因此没有问题.

示例:A String.可以String毫无顾虑地传递两个线程,因为它们都不能以任何方式改变它.

不需要复制构造函数

...因为副本是改变它的唯一方法.每个"修改"操作的不可变对象的一种常见设计模式,用于制作副本然后对新对象执行操作.

复制构造函数通常用于要更改的对象,而不会影响原始对象.对于不可变对象,总是如此(根据定义).

在这种情况下String,所有方法和+操作符都返回新的Strings.

不需要克隆的实现

往上看.

当用作场时,不需要防御性地复制

从前我做过傻事.我在List中有一组枚举:

private static final List<Status> validStatuses;

static {
  validStatuses = new ArrayList<Status>();
  validStates.add(Status.OPEN);
  validStates.add(Status.REOPENED);
  validStates.add(Status.CLOSED);
}
Run Code Online (Sandbox Code Playgroud)

此列表是从方法返回的:

public static List<Status> getAllStatuses() {
  return validStates;
}
Run Code Online (Sandbox Code Playgroud)

我检索了该列表,但只想在界面中显示打开状态:

List<Status> statuses = Status.getAllStatuses();
statuses.remove(Status.CLOSED);
Run Code Online (Sandbox Code Playgroud)

很棒,它有效!等等,现在所有状态列表只显示那两个 - 即使页面刷新后!发生了什么?我修改了一个静态对象.哎呀.

我本可以在返回对象上使用防御性复制getAllStatuses.或者,我可以首先使用像Guava的ImmutableList这样东西:

private static final List<Status> validStatuses =
    ImmutableList.of(Status.OPEN, Status.REOPENED, Status.CLOSED);
Run Code Online (Sandbox Code Playgroud)

然后当我做了一些愚蠢的事情:

List<Status> statuses = Status.getAllStatuses();
statuses.remove(Status.CLOSED);  // Exception!
Run Code Online (Sandbox Code Playgroud)

总是有"失败原子性"(Joshua Bloch使用的术语):如果一个不可变对象抛出一个异常,它就永远不会处于不受欢迎或不确定的状态.

因为永远不能修改类,所以通过修改发出的所有状态都是完整的限定对象(因为它们不能更改,所以它们必须始终处于合格状态才有用).异常不会发出新对象,因此您永远不会有不受欢迎或不确定的状态.