Java学习笔记-简单说说深克隆和浅克隆

什么是浅克隆与深克隆

简单点说浅克隆是一个不完善的克隆,内部分成员没有完成克隆复制,从而造成克隆者与被克隆对象的数据没有完全分离产生数据交叉混乱的问题。深克隆就是解决浅克隆的问题。

为什么会出现浅克隆问题

之所以出现浅克隆的问题,其根本原因是Java中引用类型和基本类型的赋值操作不同。

引用类型和基本类型的赋值操作
// 基本类型
int a = 10;
int b = a;//b=20
b = 20;//b=20,a=10
// 引用类型
Student aStu=new Student("张三");//aStu.name="张三"
Student bStu=aStu;//bStu.name="张三",aStu.name="张三"
bStu.name="李四";//bStu.name="李四",aStu.name="李四"

产生如此结果的原因是:
在这里插入图片描述
变量a和变量b都有自己的空间,修改b当然不会影响到a,但是在引用赋值时不会将其内容复制一遍,仅仅将其地址进行复制,因此两个引用实际指向的是相同的空间,就会出现修改bStu成员会影响到aStu的成员的现象,这显然不是我们想看到的结果。

浅克隆与深克隆进一步分析

浅克隆就是只用赋值进行数据克隆,此种克隆方法在克隆基本类型的成员时没用问题,但是在克隆引用类型的成员时就会出现上述问题。
深克隆就是解决浅克隆问题,其特点是在克隆引用类型的成员时不使用简单赋值方法,而是先将引用的数据复制一份再赋值。

代码实例

浅克隆
public class DeepAShallowClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student aStu = new Student(11,"张三",new Address("北京","王家小区"));
        Student bStu = (Student) aStu.clone();
        bStu.setAge(12);
        bStu.setName("李四");
        bStu.getAdr().setCity("深圳");
        System.out.println(aStu);
        System.out.println("aStu Name hashCode:" + aStu.getName().hashCode());
        System.out.println("aStu Address hashCode:" + aStu.getAdr().hashCode());
        System.out.println(bStu);
        System.out.println("bStu Name hashCode:" + bStu.getName().hashCode());
        System.out.println("bStu Address hashCode:" + bStu.getAdr().hashCode());
    }
}
class Student implements Cloneable{
    private int age;
    private String name;
    private Address adr;
    public Student(int age, String name, Address adr) {
        this.age = age;
        this.name = name;
        this.adr = adr;
    }

    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 getAdr() {
        return adr;
    }

    public void setAdr(Address adr) {
        this.adr = adr;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", adr=" + adr +
                '}';
    }
}

class Address implements Cloneable {
    String City;
    String Community;

    public Address(String city, String community) {
        City = city;
        Community = community;
    }

    public void setCity(String city) {
        City = city;
    }

    @Override
    public String toString() {
        return "Address{" +
                "City='" + City + '\'' +
                ", Community='" + Community + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        System.out.println("adr clone");
        return super.clone();
    }
}

执行结果

Student{age=11, name='张三', adr=Address{City='深圳', Community='王家小区'}}
aStu Name hashCode:774889
aStu Address hashCode:610998173
Student{age=12, name='李四', adr=Address{City='深圳', Community='王家小区'}}
bStu Name hashCode:842061
bStu Address hashCode:610998173

super.clone()方法只进行简单的赋值操作,结果中能看到两个对象的Address成员的地址是相同的(哈希值一定程度上可以当做地址看待),可以得出结论两个Address成员在内存中其实是一个实例,因此在bStu在更改其Address的内容时会影响到aStu。

深克隆
public class DeepAShallowClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student aStu = new Student(11,"张三",new Address("北京","王家小区"));
        Student bStu = (Student) aStu.clone();
        bStu.setAge(12);
        bStu.setName("李四");
        bStu.getAdr().setCity("深圳");
        System.out.println(aStu);
        System.out.println("aStu Name hashCode:" + aStu.getName().hashCode());
        System.out.println("aStu Address hashCode:" + aStu.getAdr().hashCode());
        System.out.println(bStu);
        System.out.println("bStu Name hashCode:" + bStu.getName().hashCode());
        System.out.println("bStu Address hashCode:" + bStu.getAdr().hashCode());
    }
}
class Student implements Cloneable{
    private int age;
    private String name;
    private Address adr;
    public Student(int age, String name, Address adr) {
        this.age = age;
        this.name = name;
        this.adr = adr;
    }

    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 getAdr() {
        return adr;
    }

    public void setAdr(Address adr) {
        this.adr = adr;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        Student adr=(Student)super.clone();
        adr.adr=(Address)this.adr.clone();
        return adr;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", adr=" + adr +
                '}';
    }
}

class Address implements Cloneable {
    String City;
    String Community;

    public Address(String city, String community) {
        City = city;
        Community = community;
    }

    public void setCity(String city) {
        City = city;
    }

    @Override
    public String toString() {
        return "Address{" +
                "City='" + City + '\'' +
                ", Community='" + Community + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        System.out.println("adr clone");
        return super.clone();
    }
}

执行结果

Student{age=11, name='张三', adr=Address{City='北京', Community='王家小区'}}
aStu Name hashCode:774889
aStu Address hashCode:610998173
Student{age=12, name='李四', adr=Address{City='深圳', Community='王家小区'}}
bStu Name hashCode:842061
bStu Address hashCode:2047329716

在结果中可以看出两个对象的Address成员的地址是不同,二者就不会相互影响了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值