【问题标题】:First time creating a copy method第一次创建复制方法
【发布时间】:2016-10-29 20:13:08
【问题描述】:

我正在尝试创建一个复制方法,但我所拥有的似乎太简单了,我认为它基本上什么都不做。

public Validation copy(Validation newValidation){return newValidation;}

如果这样实现的话:

Validation x = new Validation(); 
Validation y = x.copy(x);

然后确保 y 具有 x 的所有方法/变量,并且在使用 y 中的变量时,我不会影响 x 中的变量。我有一种感觉,我想要的是一种“深拷贝”方法,我在这里找到了一篇关于它的帖子:Creating a deep copy method, Java 但那个人对他们的方法没有任何论据,所以我不知道它实际上是如何复制的。

【问题讨论】:

标签: java clone


【解决方案1】:

是的,除了返回已传递的相同引用之外,它什么也不做。

您可能正在寻找Object#clone()* 方法:

public Validation copy(Validation newValidation) {
    return newValidation.clone();
}

在 95% 的情况下,这是针对不同类型任务的最合适和最合适的解决方案。如果没有必要,你不应该重新发明轮子。

正如 Java 文档所说:

...此方法执行此对象的“浅拷贝”,而不是“深拷贝”操作。

...返回之前可能需要修改super.clone返回的对象的一个​​或多个字段。

Validation y = x.copy(x);

您不应将x 传递给copy 方法,因为当您在x 实例上调用此方法时,您可以在类中访问this,在这种情况下,它代表你的x

Validation y = x.clone();

对于“浅拷贝”,前面的示例很好,但是对于“深拷贝”,您需要覆盖默认的Object#clone() 行为:

class A implements Cloneable {
    
    public @Override A clone() throws CloneNotSupportedException {
        return (A)super.clone(); // or or another implementation
    }
    
}

class Validation implements Cloneable {

    // an example of a reference-type field
    private A a; // with a setter

    public @Override Validation clone() throws CloneNotSupportedException {
        Validation newClone = new Validation();

        // note that the `A` class has to implement the `Cloneable`
        // and override the `clone` method making it `public`
        newClone.setA(this.a.clone());

        return newClone;
    }
    
}

*不要忘记实现Cloneable 接口以允许克隆。

阅读:Effective Java, Item 11: Override clone judiciously.

【讨论】:

  • 哦,好吧,所以这会产生一个重复的对象,但其变量的引用与第一个对象不同?
  • @Redcoatwright,不,实例字段引用将与原始对象中的相同
  • 乔什·布洛赫说clone is broken,你应该use a copy-constructor instead
  • @Andreas,我们应该分层使用复制构造函数进行“深度复制”吗?
  • 对于深拷贝,您应该使用任何可用于复制作为对象组合一部分的可修改嵌套对象的方法。
【解决方案2】:

Java api 有一个Cloneable 接口。Object 有一个 clone 方法,只有在子类中重写它时才能访问,它也实现了 Cloneable 接口。您的方法并没有真正创建副本,因为“副本”指向原始实例。

假设我复制了Validation

Validation v = new Validation();
v.setId(1);
Validation valid = v.copy(v);
valid.setId(2);

现在 v 中的 id 也会改变,因为 valid 指向 v

但是clone-Method 会进行深层复制。这是一个小例子:

public class Product {

private int id;
private String name;

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

@Override
public String toString() {
    return "Product{" + "id=" + id + ", name=" + name + '}';
}

@Override
protected Object clone() throws CloneNotSupportedException {
    Product p = new Product();
    p.setId(id);
    p.setName(name);
    return p;
}   

}

public static void main(String[] args) {
    Product p = new Product();
    try {
        Product clone = (Product) p.clone();
        System.out.println(clone.toString());
    } catch (CloneNotSupportedException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
}

【讨论】:

  • 抱歉,这可能有点超出我的想象。 “投掷”有什么作用?
  • 有一个不好的例子,您是否意识到克隆实例将具有与原始实例相同的实例引用?对于原始的int 字段,由于String 池化,它并不像String 那样重要。因此,在这种情况下,标准 Objects clone 具有相同的行为,并进行了一些优化。
  • @Redcoatwright,CloneNotSupportedException 是一个经过检查的异常,当您的类不提供克隆(未实现 Cloneable 接口)时将抛出该异常
  • 乔什·布洛赫说clone is broken,你应该use a copy-constructor instead
  • @AndrewTobilko yes 在这种情况下调用super.clone() 可能也能正常工作,因为id 是原始的并且String 是不可变的,但是如果Product 类有另一个引用,假设Price 为字段,那么超类中的克隆方法将不起作用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-18
  • 2014-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多