gpt4 book ai didi

java - Effective Java 声称 elements.clone() 就足够了

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:44:31 27 4
gpt4 key购买 nike

我正在阅读 Joshua Bloch 的 Effective Java,第 2 版,第 11 条:明智地覆盖克隆。

在第 56 页,他试图解释当我们重写某些类(如集合类)的 clone() 时,我们必须复制它的内部结构。然后他给出了设计类Stack的例子:

public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {...}
public void push(Object e) {...}
public Object pop() {...}
private void ensureCapacity() {...} //omitted for simplicity
}

他声称,如果我们简单地使用 super.clone() 来克隆一个 Stack,生成的 Stack 实例“将在其大小字段中具有正确的值,但是它的元素字段将引用与原始 Stack 实例相同的数组。修改原始实例将破坏克隆中的不变量,反之亦然。您很快会发现您的程序产生无意义的结果或抛出 NullPointerException ”现在看来很公平。但是他随后给出了一个“正确实现”的例子,这让我很困惑:

@Override public Stack clone() {
try {
Stack result = (Stack) super.clone();
result.elements = elements.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}

现在它与 super.clone() 有何不同?我知道,新的 Stack.element 将是一个与旧的完全不同的引用;但是数组的“内部结构”仍然是一样的,不是吗?数组 result.element 的实际元素仍然指向原始的 Object 引用。这仍然会导致在更改原始文件时破坏克隆的不变量,反之亦然,不是吗?我错过了什么吗?

最佳答案

Now how is that different from super.clone()?

因为数组现在不同了。如果两个 Stack 共享同一个数组,那么当一个在堆栈中添加或从堆栈中删除时,另一个 Stack 中的 size 字段不会更新, 导致差异。

数组的对象本身并没有被克隆。这是故意的,因为它们不需要被克隆。预计两个 Stack - 或者实际上任何两个 Collection - 可以包含对相同对象的引用。使用此代码您会得到相同的行为:

Foo foo = new Foo()
Stack stackOne = new Stack();
Stack stackTwo = new Stack();
stackOne.push(foo);
stackTwo.push(foo);

这不是天生的问题,通常是理想的行为。

关于java - Effective Java 声称 elements.clone() 就足够了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51516005/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com