【问题标题】:Java: Shallow Copy (Cloning) not working for me?Java:浅拷贝(克隆)对我不起作用?
【发布时间】:2020-04-26 04:16:42
【问题描述】:

根据定义:

浅拷贝是一种我们只将字段值从一个对象复制到另一个对象的拷贝。它们是不同的对象,但问题是当我们更改任何原始地址的属性时,这也会影响到 shallowCopy 的地址。

我试图查看对象 1 和对象 2 的值是否相同,所以尝试跟随但无法这样做。

public class TestClone implements Cloneable {
    private String a;

    public String getA() {
        return a;
    }


    public void setA(String a) {
        this.a = a;
    }


    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

主程序:

package com.test;

public class MainTestClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        TestClone clone = new TestClone();
        clone.setA("RABA");

        TestClone clone2 = (TestClone) clone.clone();
        System.out.println(clone.getA());
        System.out.println(clone2.getA());
        System.out.println("---------------------------");
        clone.setA("DABA");
        System.out.println(clone.getA());
        System.out.println(clone2.getA());
        System.out.println("---------------------------");
        clone2.setA("Clone2 RABA DABA");
        System.out.println(clone.getA());
        System.out.println(clone2.getA());

    }
}

输出:

RABA
RABA
---------------------------
DABA
RABA <--- It does not change to DABA
---------------------------
DABA <--- No Changes here
Clone2 RABA DABA

【问题讨论】:

标签: java clone shallow-copy


【解决方案1】:

我认为真正的问题是您断章取义并误解了以下定义:

“浅拷贝是我们只将字段的值从一个对象复制到另一个对象。它们是不同的对象,但问题是当我们更改任何原始地址的属性时,这也会影响 shallowCopy 的地址。”

这显然是指一些你没有引用的例子。 (因此我的评论是你已经断章取义了!)

要使此描述正确,“原始地址”属性必须是与您正在克隆的对象分开的字段。我想这个例子是这样的:

public class User implements Cloneable {
    String name;
    Address address; 
    ...
    public User clone() {
        return (User)(super.clone());
    }
}

public class Address {
    String street;
    String city;
    String zipCode;
}

他们正在这样做:

Address address = new Address(...);
User user = new User("Fred", address);
User shallowCopy = user.clone();

然后

user.getAddress().setZipCode(...);

并观察到这会更改与 原始和克隆的 User 对象相关联的邮政编码。

请注意,我们正在更改 Address 的属性,而不是 User 的属性。正如引用的文字所说的那样。


但你的例子不同。因为您正在(分别)更改原始对象和克隆对象的字段。并观察分配一个不会影响另一个。

你所做的相当于

shallowCopy.setAddress(new Address(...));

如果你这样做了,那么shallowCopy 引用的对象将不再是user 引用的对象的浅表副本,user.getAddress().setZipCode(...) 将不再影响shallowCopy 的邮政编码或反之亦然

简而言之,您看到与定义所说的不同的原因是您在不同的事情。

克隆完全按照指定的方式工作。问题是你误解或误用了浅拷贝的定义。

【讨论】:

    【解决方案2】:

    浅拷贝是关于共享内部参考。如果您直接更改引用,则克隆将保留在旧引用上,因为它是不同的对象。

    这就是为什么在 Java 中称为浅拷贝或浅克隆。如果只有原始类型字段或不可变对象,那么 Java 中的浅拷贝和深拷贝没有区别。这就是为什么在这里你实际上有一个深层副本。

    如果您将String 替换为Date,然后修改日期内容(不是引用......像这样obj1.date().setTime(1) 的内容,克隆对象将反映更改,因为它指向相同的Date参考。

    我们可以看到这样的副本

    浅拷贝clone2.date = clone.date

    关于深拷贝clone2.date=new Date(clone.getTime());

    【讨论】:

      【解决方案3】:

      无论你实现的是什么只是浅拷贝。更改原始对象的属性不会影响复制对象的状态,因为它仅包含不可变字段。 如果它包含任何可变对象,它将同时影响它们

      如果您尝试添加任何 Class 类型的另一个字段并尝试更改该类的字段值,则更改将反映在 clone 以及 clone2 对象中。

      【讨论】:

        【解决方案4】:
        super.clone
        

        根据 Java 文档

        创建并返回此对象的副本。

        因此,您对旧对象所做的任何更改都将独立于新克隆的对象。 所以 clone 、 clone2 是独立的 Java 对象,保存在不同的内存空间中。

        如果您正在寻找将更改复制到 clone2 将两个引用指向同一个对象。 例如

        TestClone clone2 = clone;
        

        【讨论】:

        • 谢谢。我正在尝试实现这样的声明,即在浅拷贝中,我们对对象所做的更改也将在克隆引用中看到。
        • 克隆不是正确的选择,您可以使用“TestClone clone2 = clone;”它会达到目的
        • hence whatever changes you do to old object would be independent of the new object 不完全正确。例如,如果字符串被日期替换并且您修改了日期内容(不更改引用),则克隆将看到相同的更改。
        • @CodeScale 你确定两个克隆的对象共享相同的内存吗?
        • 浅拷贝共享引用。如果您修改引用的内容,两者都会看到变化。
        猜你喜欢
        • 2011-09-05
        • 2011-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多