JAVA复制,重点分析下浅拷贝和深拷贝

本文详细介绍了Java中对象复制的三种方式:直接赋值、浅拷贝和深拷贝。通过实例展示了如何通过clone方法实现浅拷贝和深拷贝,并解释了两者的区别。在浅拷贝中,引用对象被共享,而在深拷贝中,引用对象会被复制。文章还探讨了如何实现深拷贝,包括对包含引用的对象进行递归复制的示例。
摘要由CSDN通过智能技术生成

    将一个对象的引用复制给另一个对象,Java提供了三种复制方式,即:直接赋值、浅拷贝、深拷贝。

1、直接赋值

    直接使用=赋值,即A a1 = a2,复制的是对象的引用,a1和a2指向的是同一个对象,当a1发生变化时,a2也会随之变化。

public class CopyTest {


    public static void main(String[] args){
        Person p1 = new Person();
        Person p2 = p1;

        System.out.println(p1);
        System.out.println(p2);

    }
}

    输出结果为:com.cc.Person@1a93a7ca和com.cc.Person@1a93a7ca,可以看到是一样的,说明“=”赋值是引用复制,其实指向的是同一个对象。

2、浅拷贝和深拷贝

2.1 clone方法简介

    对象调用clone方法时,会复制对象,JVM会分配一个和源对象一样大小的空间,然后在这个空间里创建一个对象。和new方法创建对象的方法,有所不同。

    程序执行new方法时,会先看new操作符后面的类型,会根据具体类型,分配内存空间大小。分配完内存后,会调用构造函数,填充对象的各个域(初始化过程),构造方法返回后,对象new创建完毕,可以把对象的引用地址发布出去。

    clone第一步也是分配内存,是根据源对象,分配一个一样的内存,然后再使用源对象各个域的值填充新对象的域,填充完成后,clone方法返回,新对象创建完成,可以将对象的引用地址发布到外部。

2.2 浅拷贝和深拷贝区别

    首先我们可以先看下上面例子中的Person对象,有两个属性,age和name,如下代码:

public class Person implements Cloneable{

    private String name;
    private int age;

    public Person(){}

    public Person(int age,String name){
        this.age = age;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

    age是基本数据类型,拷贝没有什么过多的讨论,直接分配4字节的内存空间,值拷贝过来就可以了。name是个字符串类型,是个引用变量,存储了指向真正String对象的地址。

    拷贝有两种方式:直接将源对象中的引用拷贝给新对象的name字段,即是浅拷贝;根据源对象的name对象,创建一个新的相同的字符串对象,将这个新的字符串对象的引用复制给新Person对象的name字段,即是深拷贝。

    图如下:

    

    代码验证如下:

public class CopyTest2 {

    public static void main(String[] args) throws CloneNotSupportedException {
        Person p = new Person(23,"chen");
        Person p1 = (Person) p.clone();

        System.out.println("p.getName().hashCode(): "+p.getName().hashCode());
        System.out.println("p1.getName().hashCode(): "+p1.getName().hashCode());

        System.out.println(p.getName().hashCode() == p1.getName().hashCode()?"clone是浅拷贝":"clone是深拷贝");
    }
    
}

    打印结果为:

p.getName().hashCode(): 3052494
p1.getName().hashCode(): 3052494
clone是浅拷贝

    说明,clone是浅拷贝,String对象不可变性质,重新set时,就会实现String对象的重新创建。

2.3 深拷贝的实现

    要实现对象的深拷贝,需要重写Cloneable接口的clone方法,不仅仅是要拷贝引用地址,还需要拷贝引用变量。

public class Address implements Cloneable{

    private String city;
    private String country;

    public Address(String city,String country){
        this.city = city;
        this.country = country;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

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


public class User implements Cloneable{

    private String name;

    private Address address;

    public User(String name,Address address){
        this.name = name;
        this.address = address;
    }

    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;
    }

    @Override
    public User clone() throws CloneNotSupportedException{
        User user = (User) super.clone();

        user.setAddress(this.address.clone());

        return user;
    }
}


public class MyTest {

    public static void main(String[] args) throws CloneNotSupportedException {

        Address address = new Address("南京","中国");
        User user = new User("cc",address);

        User copyUser = user.clone();

        copyUser.setName("tt");
        copyUser.getAddress().setCity("扬州");

        System.out.println("1"+user.getAddress().getCity());
        System.out.println("2"+copyUser.getAddress().getCity());

        System.out.println("3"+user.getName());
        System.out.println("4"+copyUser.getName());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值