为什么不在被覆盖的 .clone 中投射?

2022-09-02 21:28:02

我了解Java克隆的工作原理以及反对使用它的论据。假设我无论如何都要使用它。

为了方便起见,我想为类 Foo 编写一个克隆方法,如下所示:

@Override
public Foo clone(){
    Foo f = (Foo)super.clone();
    //Replace mutable fields
    return f;
}

据我所知,这将是安全的。但是,我注意到API中的可克隆类不这样做。这是有原因的吗,这是不好的风格吗?


答案 1

早在Java 5之前,协变返回类型根本不允许,所以甚至不会编译。由于很久以前就已经写了很多类,这可能是大多数情况的原因。Foo clone()Cloneable

我怀疑较新的类不会仅仅因为已知是相当少的而使用它,并且当人们很少使用它时,他们甚至不认为他们可以投射它。他们发现了一些“如何实现 clone()”的问题,并以老式的方式编写代码。clone()


答案 2

Object.clone()创建一个新对象,其中所有字段的值都与原始字段相同。对于引用类型的字段,这意味着新字段只是对与原始对象相同的对象的引用。它不字段。因此,在许多情况下,默认实现会导致共享数据,这可能是不希望的。例如,如果使用默认实现,则最终会有两个实例共享同一个支持数组。cloneArrayList.clone()ArrayList

如果对象的所有字段都是不可变的,则最好将 的结果简单地转换为适当的类型。super.clone()