引言

在某些场景中,我们需要获取到一个对象的拷贝用于某些处理。这时候就可以用到Java中的Object.clone方法进行对象复制,得到一个一模一样的新对象。但是在实际使用过程中会发现:当对象中含有可变的引用类型属性时,在复制得到的新对象对该引用类型属性内容进行修改,原始对象响应的属性内容也会发生变化,这就是"浅拷贝"的现象。

浅拷贝的例子

Address类:clone/Address.java

package clone;

public class Address implements Cloneable{//实现cloneable接口
    private String province;
    private String city;
    public Address() {
        
    }
    public Address(String province, String city) {
        this.province = province;
        this.city = city;
    }
    public Address clone() throws CloneNotSupportedException {
        Address newAdd = (Address)super.clone();
        return newAdd;
    }
    
    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String toString() {
        return "Province:"+province+"   city:"+city;
    }
}

student类:clone/student.java

package clone;

public class student implements Cloneable{
    private String name;//String被声明为final,是不可变类型,无法修改,所以就算是浅复制也不影响。
    private int age;//基本类型,clone的时候直接copy
    private Address address;//Address不是基本类型,并且可变,默认的clone的时候只会复制一个引用,这样clone前后的两个对象都引用同一个Address实例对象。
    public student() {
        
    }
    public student(String name,int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    public student clone() throws CloneNotSupportedException {
        student newStu = (student) super.clone();
        newStu.address = (Address) address.clone();//不加这一句,对于Address来说就是一个浅复制。
        return newStu;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    public String toString() {
        return "name:"+name+"   age:"+age+"Address Info:"+address.toString();
    }
}

test类: clone/test.java

package clone;

public class test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address add = new Address("四川","成都");
        student a = new student("小明",18,add);
        
        student b = a.clone();//克隆a,赋值给b
        add.setCity("广安");//浅复制的话,a和b都引用add这个实例对象,则此次修改值势必会影响a和b。深复制则不影响。
        System.out.println(a.toString());
        System.out.println(b.toString());
    }
}

输出

name:小明   age:18Address Info:Province:四川   city:广安
name:小明   age:18Address Info:Province:四川   city:成都

从输出结果来看,对add实例对象的修改并没有影响到b这个引用变量,所以本次clone不是浅复制。