概念
浅拷贝:创建一个对象,然后将当前对象的非静态字段复制出来,形成一个新对象。如果字段是值类型的,那么对该字段执行复制,如果该字段是引用类型的,则复制引用但不复制引用的对象内容。因此,原始对象及其副本对象的非基本数据类型的属性会引用同一个对象。
代码
@Data
public class Person implements Cloneable{
private String name;
private int id;
private Person child;
@Override
public Person clone(){
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
```java
public class TestClone {
@Test
public void testClone(){
Person person = new Person();
person.setId(1);
person.setName("小明");
Person child = new Person();
child.setId(2);
child.setName("小龙");
person.setChild(child);
Person clone = person.clone();
System.out.println("刚克隆好时person:"+person);
System.out.println("刚克隆好时clone:"+clone);
System.out.println("刚克隆好时person child hashcode:"+person.getChild().hashCode());
System.out.println("刚克隆好时clone child hashcode:"+clone.getChild().hashCode());
System.out.println("刚克隆好时person name hashcode:"+person.getName().hashCode());
System.out.println("刚克隆好时clone name hashcode:"+clone.getName().hashCode());
clone.setName("小明2");
System.out.println("克隆对象修改name之后person name hashcode:"+person.getName().hashCode());
System.out.println("克隆对象修改name之后clone name hashcode:"+clone.getName().hashCode());
System.out.println("克隆对象修改name之后person:"+person);
System.out.println("克隆对象修改name之后clone:"+clone);
clone.getChild().setName("小龙2");
System.out.println("克隆对象的child属性修改name之后person:"+person);
System.out.println("克隆对象的child属性修改name之后clone:"+clone);
}
输出结果解释
前四个输出
System.out.println("刚克隆好时person:"+person);
System.out.println("刚克隆好时clone:"+clone);
System.out.println("刚克隆好时person child hashcode:"+person.getChild().hashCode());
System.out.println("刚克隆好时clone child hashcode:"+clone.getChild().hashCode());
刚克隆好时person:Person(name=小明, id=1, child=Person(name=小龙, id=2, child=null))
刚克隆好时clone:Person(name=小明, id=1, child=Person(name=小龙, id=2, child=null))
刚克隆好时person child hashcode:45726990
刚克隆好时clone child hashcode:45726990
1.这里刚克隆好,原始数据和clone数据的的child的hashcode一样,说明person和clone的child是同一个对象。
中间的输出
System.out.println("刚克隆好时person name hashcode:"+person.getName().hashCode());
System.out.println("刚克隆好时clone name hashcode:"+clone.getName().hashCode());
clone.setName("小明2");
System.out.println("克隆对象修改name之后person name hashcode:"+person.getName().hashCode());
System.out.println("克隆对象修改name之后clone name hashcode:"+clone.getName().hashCode());
System.out.println("克隆对象修改name之后person:"+person);
System.out.println("克隆对象修改name之后clone:"+clone);
* 刚克隆好时person name hashcode:756703
* 刚克隆好时clone name hashcode:756703
* 克隆对象修改name之后person name hashcode:756703
* 克隆对象修改name之后clone name hashcode:23457843
* 克隆对象修改name之后person:Person(name=小明, id=1, child=Person(name=小龙, id=2, child=null))
* 克隆对象修改name之后clone:Person(name=小明2, id=1, child=Person(name=小龙, id=2, child=null))
2.刚克隆好时person和clone对象的name属性hashcode是一样的,此时他们俩的name是同一个对象,修改clone对象的name之后,clone对象的name的hashcode变了,说明已经换了一个对象。
3.这里说明String类型的数据修改并不会影响原始数据,因为String每次修改都是重新创建了新的String对象,这里是吧新的String对象的引用给了clone对象的name,所以地址也变了,但不会影响person的。
最后的输出
clone.getChild().setName("小龙2");
System.out.println("克隆对象的child属性修改name之后person:"+person);
System.out.println("克隆对象的child属性修改name之后clone:"+clone);
* 克隆对象的child属性修改name之后person:Person(name=小明, id=1, child=Person(name=小龙2, id=2, child=null))
* 克隆对象的child属性修改name之后clone:Person(name=小明2, id=1, child=Person(name=小龙2, id=2, child=null))
4.修改child属性的name之后,发现原始数据person和clone数据的name都变了,也就跟上面1所说的,person和clone的child是同一个对象。
疑问
以下结果是什么原因呢?
刚克隆好时person hashcode:90581327
刚克隆好时clone hashcode:90581327
克隆对象修改name之后person hashcode:90581327
克隆对象修改name之后clone hashcode:1429948587
最后person hashcode:1456022457
最后clone hashcode:-1499577579