浅谈 ---- Java深拷贝与浅拷贝

106 阅读3分钟

1. 浅拷贝

对于值类型来说,浅拷贝是把该值复制一份,但是对于引用类型来说,浅拷贝仅仅是把引用的地址复制一份,而复制之后引用地址所指的对象和原始引用地址所指对象还是同一个,这样当对象发生修改,原始引用地址和复制引用地址所指的对象都会修改。

​例如:

package com.hfut;

/**
 * @author Chenzh
 */
public class Job implements Cloneable{

    private String jobName;

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public String getJobName() {
        return jobName;
    }
}

package com.hfut;

/**
 * @author Chenzh
 */
public class Subject implements Cloneable {

    private String stuName;
    private Job job;

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    public void setJob(Job job) {
        this.job = job;
    }

    public String getStuName() {
        return stuName;
    }

    public Job getJob() {
        return job;
    }

    @Override
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

package com.hfut;

/**
 * @author Chenzh
 */
public class Copy {
    public static void main(String[] args) {
        // 原始对象
        Subject sub1 = new Subject();
        sub1.setStuName("多隆");
        Job job = new Job();
        job.setJobName("程序员");
        sub1.setJob(job);

        // 浅赋值对象
        Subject sub2 = (Subject) sub1.clone();
        boolean res = sub1 == sub2;

        System.out.println("原始对象是否和浅复制对象一样:" + res);
        System.out.println("原始对象的属性值:" + sub1.getStuName());
        System.out.println("原始对象的属性值:" + sub1.getJob().getJobName());
        System.out.println("浅拷贝对象的属性值:" + sub2.getStuName());
        System.out.println("浅拷贝对象的属性值:" + sub2.getJob().getJobName());
        System.out.println("*************对原始对象进行修改******************");

        sub1.setStuName("阿珂");
        job.setJobName("运营工程师");
        sub1.setJob(job);
        System.out.println("原始对象的属性值:" + sub1.getStuName());
        System.out.println("原始对象的属性值:" + sub1.getJob().getJobName());
        System.out.println("浅拷贝对象的属性值:" + sub2.getStuName());
        System.out.println("浅拷贝对象的属性值:" + sub2.getJob().getJobName());
    }
}

原始对象是否和浅复制对象一样:false
原始对象的属性值:多隆
原始对象的属性值:程序员
浅拷贝对象的属性值:多隆
浅拷贝对象的属性值:程序员
*************对原始对象进行修改******************
原始对象的属性值:阿珂
原始对象的属性值:运营工程师
浅拷贝对象的属性值:多隆
浅拷贝对象的属性值:运营工程师

从上面代码可以看出,将sub1通过浅拷贝给sub2后,两个对象的地址不一样,但是属性值都一样,当sub1修改了stuName属性和引用类型的对象job发生变化后,sub1和sub2对象中的属性均发生了变化。

2. 深拷贝

对于值类型的数据来说,同浅拷贝一样,深拷贝也是把该值复制一份,但是对于引用类型来说,深拷贝会把该引用所指的对象也会复制一份,相当于创建了一个副本,这样即使原始引用地址所指的对象发生修改,新复制的对象依然不会改变。

例如:

package com.hfut;

/**
 * @author Chenzh
 */
public class Job implements Cloneable{

    private String jobName;

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public String getJobName() {
        return jobName;
    }

    @Override
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

package com.hfut;

/**
 * @author Chenzh
 */
public class Subject implements Cloneable {

    private String stuName;
    private Job job;

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    public void setJob(Job job) {
        this.job = job;
    }

    public String getStuName() {
        return stuName;
    }

    public Job getJob() {
        return job;
    }

    @Override
    public Object clone() {
        try {
            Subject subject = (Subject) super.clone();
            subject.job = (Job) job.clone();
            return subject;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

package com.hfut;

/**
 * @author Chenzh
 */
public class Copy {
    public static void main(String[] args) {
        // 原始对象
        Subject sub1 = new Subject();
        sub1.setStuName("多隆");
        Job job = new Job();
        job.setJobName("程序员");
        sub1.setJob(job);

        // 浅赋值对象
        Subject sub2 = (Subject) sub1.clone();
        boolean res = sub1 == sub2;

        System.out.println("原始对象是否和浅复制对象一样:" + res);
        System.out.println("原始对象的属性值:" + sub1.getStuName());
        System.out.println("原始对象的属性值:" + sub1.getJob().getJobName());
        System.out.println("深拷贝对象的属性值:" + sub2.getStuName());
        System.out.println("深拷贝对象的属性值:" + sub2.getJob().getJobName());
        System.out.println("*************对原始对象进行修改******************");

        sub1.setStuName("阿珂");
        job.setJobName("运营工程师");
        sub1.setJob(job);
        System.out.println("原始对象的属性值:" + sub1.getStuName());
        System.out.println("原始对象的属性值:" + sub1.getJob().getJobName());
        System.out.println("深拷贝对象的属性值:" + sub2.getStuName());
        System.out.println("深拷贝对象的属性值:" + sub2.getJob().getJobName());
    }
}

原始对象是否和浅复制对象一样:false
原始对象的属性值:多隆
原始对象的属性值:程序员
深拷贝对象的属性值:多隆
深拷贝对象的属性值:程序员
*************对原始对象进行修改******************
原始对象的属性值:阿珂
原始对象的属性值:运营工程师
深拷贝对象的属性值:多隆
深拷贝对象的属性值:程序员

从上面代码可以看出,将sub1通过浅拷贝给sub2后,两个对象的地址不一样,但是属性值都一样,当sub1修改了stuName属性和引用类型的对象job发生变化后,sub1发生了变化,但是sub2未发生变化。