根据定义:
浅表副本是我们只将字段值从一个对象复制到另一个对象的副本。它们是不同的对象,但是问题在于,当我们更改任何原始地址的属性时,这也会影响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
答案 0 :(得分:2)
我认为真正的问题是您从上下文中脱离了以下定义,并误解了它:
“浅表复制是一种复制,其中我们仅将字段的值从一个对象复制到另一个对象。它们是不同的对象,但是问题是当我们更改任何原始地址的属性时,这也会影响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
或反之亦然。
简而言之,您看到与定义中所说的有所不同的原因是您正在做。
克隆完全按照指定的方式工作。问题是您误解或错误使用了浅表副本的定义。
答案 1 :(得分:1)
浅拷贝是关于共享内部引用。如果直接更改参考,则克隆将保留在旧参考上,因为它是一个不同的对象。
这就是Java中浅拷贝或浅克隆的名称的原因。如果只有原始类型字段或不可变对象,则Java中的浅表副本和深表副本之间没有区别。这就是为什么您这里实际上有一个深层副本。
如果您将String
替换为Date
,然后修改日期内容(而不是引用内容,则类似obj1.date().setTime(1)
的内容,克隆对象将反映更改,因为它指向到相同的Date
参考。
我们可以看到这样的副本
在浅拷贝clone2.date = clone.date
在深层复制clone2.date=new Date(clone.getTime());
答案 2 :(得分:1)
您实施的只是“浅复制”。更改原始对象的属性不会影响复制对象的状态,因为它仅包含不可变字段。 如果其中包含任何易变的对象,则将同时影响它们。
如果您尝试添加任何Class类型的另一个字段并尝试更改该类的field的值,那么更改将反映在clone以及clone2对象中。
答案 3 :(得分:0)
super.clone
根据Java文档
创建并返回此对象的副本。
因此,您对旧对象所做的任何更改都将独立于新克隆的对象。 因此clone和clone2是保存在不同内存空间中的单独的Java对象。
如果要复制对clone2的更改,请将两个引用都指向同一对象。 例如
TestClone clone2 = clone;