Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java不可变对象_Java_String_Object_Wrapper_Immutability - Fatal编程技术网

Java不可变对象

Java不可变对象,java,string,object,wrapper,immutability,Java,String,Object,Wrapper,Immutability,我正在学习不变性的概念 我理解,一旦对象被创建,不可变对象就不能更改其值 但我不理解不可变对象的以下用法。 是的 是自动线程安全的,并且没有同步问题如何?证明? 不需要复制构造函数如何?有什么例子吗? 不需要克隆如何实现?有什么例子吗? 当用作字段时不需要防御性复制如何?有什么例子吗? 始终具有“失败原子性”(Joshua Bloch使用的术语):如果不可变对象抛出异常,它永远不会处于不希望的或不确定的状态如何?有什么例子吗? 有人能用例子详细解释一下这些要点吗 谢谢 。是自动线程安全的,没

我正在学习不变性的概念

我理解,一旦对象被创建,不可变对象就不能更改其值

但我不理解不可变对象的以下用法。

是的

  • 是自动线程安全的,并且没有同步问题<代码>如何?证明?
  • 不需要复制构造函数<代码>如何?有什么例子吗?
  • 不需要克隆
    如何实现?有什么例子吗?
  • 当用作字段时不需要防御性复制
    如何?有什么例子吗?
  • 始终具有
    “失败原子性”(Joshua Bloch使用的术语)
    :如果不可变对象抛出异常,它永远不会处于不希望的或不确定的状态<代码>如何?有什么例子吗?
有人能用例子详细解释一下这些要点吗

谢谢

。是自动线程安全的,没有同步问题

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

示例:一个
字符串
。两个线程可以毫无顾虑地传递相同的
String
,因为它们都不能以任何方式对其进行变异

不需要复制构造函数

。。。因为复制是变异它的唯一途径。为每个“修改”操作创建一个副本,然后在新对象上执行操作的不可变对象提供一个通用设计模式

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

对于
String
,所有方法和
+
操作符都返回新的
String
s

不需要克隆的实现

见上文

用作字段时不需要防御性复制

从前,我做了一件傻事。我在列表中有一组枚举:

private static final List<Status> validStatuses;

static {
  validStatuses = new ArrayList<Status>();
  validStates.add(Status.OPEN);
  validStates.add(Status.REOPENED);
  validStates.add(Status.CLOSED);
}
然后当我做了一些愚蠢的事情:

List<Status> statuses = Status.getAllStatuses();
statuses.remove(Status.CLOSED);  // Exception!
List statuses=Status.getAllStatuses();
状态。删除(状态。关闭);//例外!
始终具有“失败原子性”(Joshua Bloch使用的术语):如果不可变对象抛出异常,它永远不会处于不希望的或不确定的状态。

因为类永远不能被修改,所以修改发出的所有状态都是完整的限定对象(因为它们不能更改,所以它们必须始终处于限定状态才能有用)。异常不会发出新对象,因此您永远不会有不需要的或不确定的状态

它们是自动线程安全的,没有同步问题

是,因为Java内存模型为以下各项提供了保证:

最后一个字段还允许程序员实现线程安全的不可变对象,而无需同步。线程安全的不可变对象被所有线程视为不可变的,即使使用数据竞争在线程之间传递对不可变对象的引用

当用作字段时不需要防御性复制如何?有什么例子吗

因为它们是不可变的,所以不能修改,所以可以与外部代码共享它们(您知道它们将无法破坏对象的状态)

推论:您不需要复制/克隆不可变对象

始终具有“失败原子性”


不可变对象在正确构造后不会发生更改。因此,要么构造失败,你会得到一个异常,要么没有,你知道对象处于一致状态。

这不是一个可以用它的例子来有效解释的概念。不可变对象的优点是,您知道它们的数据无法更改,因此不必担心这一点。您可以自由地使用不可变对象,而不用担心传递它们的方法会改变它


当我们执行多线程程序时,这很方便,因为基于线程更改的数据的bug不应该自动执行线程安全的

  • 因为它们不能改变(不能变异)——任何访问它的线程都会发现对象处于相同的状态。所以不存在这样的情况:一个线程改变了对象的状态,然后第二个线程接管并改变了对象的状态,然后第一个线程毫无线索地接管,它被其他线程改变了
  • ArrayList就是一个很好的例子——如果一个线程遍历它的元素,而第二个线程删除了其中的一些元素,那么第一个线程就会抛出某种并发异常。使用不可变列表可以防止这种情况
复制构造函数

  • 这并不意味着它不能有一个复制构造函数。它是一个构造函数,您将同一类型的对象传递给它,然后创建新对象作为给定对象的副本。这只是一个猜测,但为什么要复制始终处于相同状态的对象呢
克隆的实施

  • 同样的问题是,总是处于相同状态的克隆对象通常只占用内存空间。但如果您想从immutable中创建可变对象,您可以这样做
  • 很好的例子是集合,您可以从immutable中生成可变集合
防御性复制

  • 防御性复制是指在将对象设置为字段时,创建与原始对象相同类型的新对象

我已投票决定关闭。这五个问题合在一起,每个问题都需要广泛详细的答案。不知道为什么会有三张赞成票。这是家庭作业吗?另外,请注意,同时还有许多问题
List<Status> statuses = Status.getAllStatuses();
statuses.remove(Status.CLOSED);
private static final List<Status> validStatuses =
    ImmutableList.of(Status.OPEN, Status.REOPENED, Status.CLOSED);
List<Status> statuses = Status.getAllStatuses();
statuses.remove(Status.CLOSED);  // Exception!
public class A
{
    private int a;

    public A(int a)
    {
        this.a = a;
    }

    public A(A original)
    {
        this.a = original.a;
    }

}