【问题标题】:Why not cast inside overridden .clone?为什么不在覆盖的 .clone 中强制转换?
【发布时间】:2016-02-02 11:08:21
【问题描述】:

我了解 Java 克隆的工作原理以及反对使用它的论点。可以说无论如何我都死心塌地地使用它。

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

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

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

【问题讨论】:

  • 请注意,这仅在您这样使用时才有用:Foo foo = ...; Foo bar = foo.clone()

标签: java clone


【解决方案1】:

嗯,这绝对不是一种糟糕的风格,事实上,自 java 1.5 发布以来最好这样做,因为协变返回类型是 作为泛型的一部分在 1.5 版中引入,这样做可以使您的 API 更易于使用(不需要强制转换)。

来源(Effective java 第 2 版)。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • API 对 clone() 的预期用途非常模糊,但它确实说:Typically, this means copying any mutable objects that comprise the internal "deep structure" of the object being cloned and replacing the references to these objects with references to the copies.,因此理想情况下,clone() 应该返回深层副本。理想但不一定...
    • 如果字段都是不可变的,那么深拷贝和浅拷贝没有区别。
    • 确实如此,但这与问题有什么关系?我有点失落。 :)
    • 它回答了这个问题。不简单地做(MyClass) super.clone() 的原因是这是一个浅拷贝,而通常需要一个深拷贝。我已经说过,在深浅拷贝没有区别的情况下可以这样做。
    • 哦,我明白了。很公平,我认为这个问题纯粹是关于为什么我们在覆盖 clone() 时不使用协变返回类型,而不是关于强制转换 super.clone()
    【解决方案3】:

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

    我怀疑较新的类不使用它只是因为众所周知clone() 很少,而且当人们很少使用它时,他们甚至不认为他们可以施放它。他们找到了一些“如何实现 clone()”的问题,并以老式的方式编写代码。

    【讨论】:

    • 好旧的“它太坏了,甚至没有人试图浪费时间试图修复它”。
    猜你喜欢
    • 1970-01-01
    • 2012-04-16
    • 2014-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    相关资源
    最近更新 更多