【问题标题】:Java clone() methodJava clone() 方法
【发布时间】:2015-07-16 16:51:48
【问题描述】:

我阅读了 J.Bloch 的 Effective Java,其中写道:

如果您为继承设计一个类,请注意,如果您选择不 提供一个行为良好的受保护克隆方法,它将是 子类不可能实现 Cloneable。

我有 A 类:

public class A{}

以及扩展A类的B类:

public class B extends A implements Cloneable {

}

所以在这种情况下我不能覆盖clone() 方法?如果是,请解释原因。

【问题讨论】:

  • 使用复制构造函数。
  • 是的,我知道复制构造函数是复制对象的更好方法..谢谢:)
  • 对于其他人:复制构造函数的替代方法是 static newInstance() 成语。但我觉得这很好奇。为什么不简单地让你的类成为自己的工厂并拥有一个非静态的newInstance() 方法呢?似乎比传入现有对象作为参数更干净;就像对象本身的副本一样(不使用损坏的clone())。
  • 过去,我有一个客户需要shallowClone()deepClone() 自定义方法,以避免java clone() 废话。他们希望它完全在他们自己的控制之下。对我来说很有意义。
  • @tgm1024 所以,在现实生活中,在所有情况下使用 clone() 方法都是个坏主意?

标签: java


【解决方案1】:

在你的情况下是的,你可以覆盖clone():

public class A {
}

public class B extends A implements Cloneable {

    @Override
    public B clone() throws CloneNotSupportedException {
        return (B) super.clone();
    }
}

并且仍然具有有效的克隆机制 - 因此,当您声明 implements Cloneable 时,您说的是实话。

然而,打破这个承诺所需要的只是给A一个private变量。

public class A {
    private int a;
}

现在你的承诺被打破了——除非 A 实现了clone,在这种情况下你可以使用super.clone()

public class A {

    private int a;

    @Override
    public A clone() throws CloneNotSupportedException {
        A newA = (A) super.clone();
        newA.a = a;
        return newA;
    }
}

public class B extends A implements Cloneable {

    private int b;

    @Override
    public B clone() throws CloneNotSupportedException {
        B newB = (B) super.clone();
        newB.b = b;
        return newB;
    }
}

基本上 - 正如 Joshua Bloch 所说 - 如果您不实现 clone 您的子类也不能(通常)。

【讨论】:

  • 这完全是不真实的。 A 中的私有字段将被Object.clone() 克隆。
【解决方案2】:

Cloneableclone() 几乎已被弃用,所以无论如何都没关系。但是,由于clone() 总是应该调用super.clone(),如果超类实现错误,子类也无法修复它。

这与无法覆盖clone() 无关,只是不会导致正确的实现。

【讨论】:

  • 您的第一条语句(Cloneable 已弃用)究竟来自哪里?
  • 关于它的大量讨论,here's 一个地方。实际上Cloneable 并没有弃用,而是损坏了
  • 好吧,我完全同意“破碎”的部分。我只是以为我错过了弃用部分。
  • @EJP 我想我在这里的想法是,如果A 不调用super.clone()(即Object.clone()),那么B 将无法调用调用它会导致不正确的实现。但是,文档似乎声明了By convention, the returned object should be obtained by calling super.clone(),所以我想它只会导致非常规实现。
  • 在我看来,从 Bloch 引用的那句话完全是错误的。也许有一些环境背景可以证明它是合格的。我没有副本,坦率地说,我从中看到的摘录并没有给我留下深刻印象。
【解决方案3】:

当然可以实现B.clone()

J. Bloch 所指的问题是(IIRC),如果没有好的A.clone() 方法,A 中的私有字段无法正确克隆到B 中。简单示例:

public class A {
  private String myText;
  public A (String myText) {
    this.myText = myText;
  }
  public String getExtendedText() {
    return "Hello something " + myText;
  }
}

public class B extends A implements Cloneable {
    private int someValue;
    // getter/setter

    public clone() {
        // how can you now provide a good clone with A.myText being cloned?
    }    
}

【讨论】:

  • A.myTextB.someValue 将被 Object.clone() 自动克隆。在这种情况下,B.clone() 除了调用super.clone() 之外不需要做任何事情。
猜你喜欢
  • 1970-01-01
  • 2018-06-10
  • 2013-06-16
  • 2011-03-11
  • 1970-01-01
  • 2011-11-26
  • 1970-01-01
  • 1970-01-01
  • 2014-05-19
相关资源
最近更新 更多