在以下代码中(复制自Java Concurrency in Practice第2章,2.5节,清单2.8):
@ThreadSafe
public class CachedFactorizer implements Servlet {
@GuardedBy("this") private BigInteger lastNumber;
@GuardedBy("this") private BigInteger[] lastFactors;
@GuardedBy("this") private long hits;
@GuardedBy("this") private long cacheHits;
public synchronized long getHits() { return hits; }
public synchronized double getCacheHitRatio() {
return (double) cacheHits / (double) hits;
}
public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = null;
synchronized (this) {
++hits;
if (i.equals(lastNumber)) {
++cacheHits;
factors = lastFactors.clone(); // questionable line here
}
}
if (factors == null) {
factors = factor(i);
synchronized (this) {
lastNumber = i;
lastFactors = factors.clone(); // and here
}
}
encodeIntoResponse(resp, factors);
}
}为什么要克隆factors和lastFactors阵列?它不能简单地写成factors = lastFactors;和lastFactors = factors;吗?仅仅因为factors是一个局部变量,然后将其传递给encodeIntoResponse,它可以修改它吗?
希望问题是清楚的。谢谢。
发布于 2012-10-05 19:09:53
这称为防御性复制。与其他数组一样,数组也是对象,因此
factors = lastFactors可以将lastFactos引用到因子,反之亦然。所以任何人都可以覆盖你的状态,而不是你的控制。举个例子:
private void filterAndRemove(BigInteger[] arr);
private void encodeIntoResponse(..., BigInteger[] factors) {
filterAndRemove(factors);
}对于我们的理论任务,filterAndRemove也会影响原始的lastFactorials。
发布于 2012-08-20 16:31:19
从基础知识中猜到的答案是:如果你计划修改对象,并且你不想修改原始对象,那么你需要克隆它,在你的例子中,factors = lastFactors.clone();完成了,因为你不想修改lastFactors,而是克隆它,并将其发送到encodeIntoResponse(resp, factors);,其中可能包含修改它的代码。
发布于 2012-10-23 23:04:27
克隆数组的唯一原因是阻止(在本例中是并发的)数组元素的修改。然而,在这种情况下,如果没有其他方法修改lastFactors引用的数组,这看起来是不可能的,这在示例中是有意义的。存储在factors和lastFactors中的数组都是由factor以完整的状态创建和返回的,并且它们的引用被分配到同步块中,这将导致它们被安全地发布。
除非encodeIntoResponse修改其factors参数的元素,否则在我看来,对clone的调用是不必要的。
https://stackoverflow.com/questions/12034370
复制相似问题