原文链接:https://blog.csdn.net/zhangjg_blog/article/details/18369201/
简单引用
new操作符的本意是分配内存。程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。
结构图如下:
public class demo1Clone {
public static void main(String[] args) {
System.out.println("复制初始化");
Person p = new Person(1001,"初始",true);
System.out.println(p);
Person p1 = p;
System.out.println(p1);
System.out.println("修改p后");
p.setId(1002);
p.setName("修改");
System.out.println(p);
System.out.println(p1);
}
}
输出结果:
浅拷贝
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换而言之,浅拷贝可以拷贝这个对象的变量,但是不能拷贝这个对象所引用的对象。可以通过clone()方法进行浅拷贝。
通过建立一个Depart类,如果想要对这个类的对象能够进行浅复制,需要进行两部操作:一是引入Cloneable接口,二是重写clone()方法。
代码如下所示:
public class demo1Clone {
public static void main(String[] args) throws CloneNotSupportedException {
Person p = new Person(1001,"职工姓名",true);
System.out.println(p);
Depart depart = new Depart(p,"IT部");
Depart depart1 = (Depart) depart.clone();
System.out.println(depart1.person);
System.out.println("depart地址:"+depart);
System.out.println("depart1地址:"+depart1);
System.out.println("person地址:"+p);
System.out.println("depart的person地址:"+depart.person);
System.out.println("depart1的person地址:"+depart1.person);
}
static class Depart implements Cloneable{
private Person person;
private String name;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Depart(Person person, String name) {
this.person = person;
this.name = name;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
通过对上面代码进行分析:depart与他的复制体depart1不是同一个地址,但是他们的引用对象person却是同一个地址。
再具体一下进行修改,将如下代码加入main函数。
depart.setName("销售部");
System.out.println("depart的名字:"+depart.getName());
System.out.println("depart1的名字:"+depart1.getName());
p.setName("刘晓燕");
System.out.println("depart中person的职工姓名:"+depart.person.getName());
System.out.println("depart1中person的职工姓名:"+depart1.person.getName());
得出输出结果:
由结果可知对于Depart中由于引用了Cloneable接口,所以是可以对一些变量进行拷贝的,但是对于Depart对象中引用对象是无法进行拷贝的,他们引用的是同一个地址的对象。
这个时候就可以考虑对于Person进一步与原对象的隔离,也就是深拷贝。
深复制
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
因此我们对上面的例子进一步操作,我们需要得到的是割裂person对于depart与他的复制对象depart1的联系,具体操作分三步:
1,Person对象引入Cloneable接口;
2,重写Person类中clone()方法;
3,在引用Person类的Depart中的clone()方法中引入新的person类。
具体代码如下所示:
public class demo1Clone {
public static void main(String[] args) throws CloneNotSupportedException {
Person p = new Person(1001,"罗宾汉",true);
System.out.println(p);
Depart depart = new Depart(p,"IT部");
Depart depart1 = (Depart) depart.clone();
System.out.println(depart1.person);
System.out.println("depart地址:"+depart);
System.out.println("depart1地址:"+depart1);
System.out.println("person地址:"+p);
System.out.println("depart的person地址:"+depart.person);
System.out.println("depart1的person地址:"+depart1.person);
depart.setName("销售部");
System.out.println("depart的名字:"+depart.getName());
System.out.println("depart1的名字:"+depart1.getName());
p.setName("刘晓燕");
System.out.println("depart中person的职工姓名:"+depart.person.getName());
System.out.println("depart1中person的职工姓名:"+depart1.person.getName());
}
static class Depart implements Cloneable{
private Person person;
private String name;
@Override
protected Object clone() throws CloneNotSupportedException {
Depart depart = (Depart) super.clone();
depart.person = (Person) person.clone();
return depart;
}
public Depart(Person person, String name) {
this.person = person;
this.name = name;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
结果如下:
我们只看最后的输出结果,很明显,depart与depart1中的person对象不再相同,这时候两个对象在他们的引用对象上发生了割裂。
但是,需要注意的是原对象的person是跟person的没有割裂的,这两个指向同一个地址。