根据JAVA文档,super.clone()在调用时返回对象的浅表副本。在下面的代码中,我有两个对象名称和 id ;和一个原始变量 num 。 当在第一个对象上调用super.clone()方法时,除了只有num的预期副本之外,它似乎还创建了对象的深层副本(name和id)。克隆对象obj后,我更改了它的名称和id字段。如果正在制作浅拷贝,则这些更改应反映在克隆对象中。我是对的吗?
public class Cloning implements Cloneable {
String name;
int num;
Integer id;
Cloning(String name,int num,Integer id)
{
this.name = name;
this.num = num;
this.id = id;
}
public Object clone()
{
try
{
return super.clone();
}
catch(CloneNotSupportedException E)
{
System.out.println(E.getMessage());
return null;
}
}
public void print()
{
System.out.println(name);
System.out.println(num);
System.out.println(id);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Cloning obj = new Cloning("Annu",203,new Integer(3));
Cloning obj1 = (Cloning)obj.clone();
obj.name = "Annu_modified";
obj.num = 204;
obj.id = new Integer(4);
obj.print();
obj1.print();
}
}
我在运行代码时得到以下输出:
Annu_modified
204
4
Annu
203
3
答案 0 :(得分:1)
name和id字段是对String和Integer类型的对象的引用。当您进行浅拷贝时,新副本指向名称和id的相同对象。
然后当你做
obj.name =“Annu_modified”;
更改obj.name以引用String类型的新对象,而obj1.name继续引用旧对象。如果您可以更改对象obj.name,则它将更改为两者。但是对于String,你不能使它成为一个所谓的不可变对象。
答案 1 :(得分:0)
尝试此测试
Cloning obj = new Cloning("Annu",203, 1000);
Cloning obj1 = (Cloning)obj.clone();
System.out.println(obj.id == obj1.id);
它打印true
,这意味着克隆对象的id指向同一个Integer实例,如果它是深度克隆则会打印false
答案 2 :(得分:0)
class Subject {
private String name;
public String getName() {
return name;
}
public void setName(String s) {
name = s;
}
public Subject(String s) {
name = s;
}
}
class Student implements Cloneable {
//Contained object
private Subject subj;
private String name;
public Subject getSubj() {
return subj;
}
public String getName() {
return name;
}
public void setName(String s) {
name = s;
}
public Student(String s, String sub) {
name = s;
subj = new Subject(sub);
}
public Object clone() {
//shallow copy
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
public class CopyTest {
public static void main(String[] args) {
//Original Object
Student stud = new Student("John", "Algebra");
System.out.println("Original Object: " + stud.getName() + " - "
+ stud.getSubj().getName());
//Clone Object
Student clonedStud = (Student) stud.clone();
System.out.println("Cloned Object: " + clonedStud.getName() + " - "
+ clonedStud.getSubj().getName());
stud.setName("Dan");
stud.getSubj().setName("Physics");
System.out.println("Original Object after it is updated: "
+ stud.getName() + " - " + stud.getSubj().getName());
System.out.println("Cloned Object after updating original object: "
+ clonedStud.getName() + " - " + clonedStud.getSubj().getName());
}
}
Output is:
Original Object: John - Algebra
Cloned Object: John - Algebra
Original Object after it is updated: Dan - Physics
Cloned Object after updating original object: John - Physics
在这个例子中,我所做的只是实现你想用Clonable接口复制的类,并覆盖Object类的clone()方法并在其中调用super.clone()。如果您观察到,对" name"所做的更改原始对象(学生类)的字段不会反映在克隆对象中,而是对" name"所做的更改。包含对象(Subject类)的字段反映在克隆对象中。这是因为克隆的对象携带Subject对象的内存地址,但不包含实际值。因此,Original对象中Subject对象的任何更新都将反映在Cloned对象中。
答案 3 :(得分:0)
让我们看看您示例中的一个部分:obj.id = new Integer(4);
。在这里,您不会更改id的内部表示 - 您将新实例分配给id引用。 Integer
和String
都是不可变的,因此很难感觉浅层与深层复制的区别。尝试添加例如一个ArrayList
属性,为了修改它,您可以例如添加新元素obj.myList.add(13);