深拷贝和浅拷贝

目录

一.Java的Cloneable和clone()方法

1.Object类中的clone()

2.实现Cloneable接口的类

3.通过clone()生成对象的特点

二.深拷贝和浅拷贝

1.浅拷贝

2.深拷贝

3.实现深拷贝的两种方法

1.一种是递归的进行拷贝

2.Json字符串的方式进行深拷贝


一.Java的Cloneable和clone()方法

1.Object类中的clone()

以下是Java中Object类中clone()方法,我们可以看到clone()方法是没有方法体的,因为clone是一个native类型的代码,具体的代码实现在JVM的c++代码中实现,Java只是调用.

2.实现Cloneable接口的类

以下是Cloneable接口的内容,我们可以看到这个接口里面并没有实际的说明内容,这个接口的实现表示实现的类重写了clone()方法,可以进行对象的克隆.

现在我们实现Cloneable接口来创建一个类,这个类重写了clone(),并且根据重写的规则,这个方法的修饰必须比protected的权限更大,因此可以使用public方法,而且Object类中返回值是Object,我们这里重写的返回值可以为Dog,因为重写的规则规定返回值必须是instanceof Object,所以返回值可以为Dog.

public class Dog implements Cloneable{
    String name;
    int age;

    public Dog() {
    }

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

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

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

现在我们尝试用Dog类中的clone方法来克隆一个完全一样的对象

    public static void main(String[] args) throws CloneNotSupportedException {
        Dog dog1 = new Dog("张选宁", 2);
        Dog dog2 = dog1.clone();
        System.out.println(dog1);
        System.out.println(dog2);
        System.out.println(dog1==dog2);
    }

现在我们来思考一个问题,dog1和dog2是否指向的是同一个对象呢?我们有什么方法来验证是否为同一个对象呢?

这里提供两种方法来判断

  1. 使用==号来进行判断

            //"==" 比较的是两个引用是否指向同一个对象
            System.out.println(dog1==dog2);//false

  2.  修改一个对象的属性,检查另一个对象的属性是否发生改变
        dog1.name="薛程朗";
        System.out.println(dog1.name); //薛程朗
        System.out.println(dog2.name); //张选宁
    

因此我们从以上两个结果可以判断出,clone()方法产生的对象是指向不同引用的.

3.通过clone()生成对象的特点

上面我们通过两个结果已经总结出来了:clone()方法产生的对象是指向不同引用的.现在我们来具体的理解以下这两个对象.

根据下面两个图我们可以很直观的看出,这两个对象的地址不一样(也就是引用不一样),当改变一个对象的属性值的时候,另一个是不会发生改变的,clone()只是产生了一个属性相同的另一个对象

那么我们再来思考一个问题 ,如果这个类中包含了其他类型的对象,这个时候这个对象该如何拷贝呢?这就引出了我们的深拷贝和浅拷贝的概念了.

二.深拷贝和浅拷贝

以下是一个包含其他对象的类

public class Person implements Cloneable {
    String name;
    //包含了其他类型的对象
    Dog dog;

    public Person() {
    }

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

    public Person(String name, Dog dog) {
        this.name = name;
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", dog=" + dog +
                '}';
    }
}

1.浅拷贝

接下来我们来验证是否克隆person1对象的时候,是否会将Person类中的Dog对象重现创建对象,还是仅仅是引用的复制(也就是地址相同的对象(同一个对象))

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("czj", new Dog("张选宁", 3));
        Person person2 = person1.clone();
        System.out.println(person1.dog==person2.dog);//ture
        person1.dog.name="薛程朗";
        System.out.println(person1.dog.name);//薛程朗
        System.out.println(person2.dog.name);//薛程朗
    }

通过验证我们可以很清楚的看到仅仅是引用的复制,本质上里面的dog对象还是同一个对象,形象一点来说,也就是一个人,通过克隆技术又克隆出来了一个一模一样的人,但他们拥有的狗还是同一个狗.

接下来我们还是通过画图来明确这种拷贝方式的原理

 这就是浅拷贝,只是将对象里面的对象引用进行了简单的拷贝,并没有将里面的对象进行new新建

接下来是网络上的定义:

浅拷贝是指只复制了对象的引用,新对象和原对象引用的是同一个对象。因此,当修改其中一个对象时,另一个对象也会受到影响。浅拷贝通常只能复制基本数据类型和对其他对象的引用,而不能复制其所引用的对象本身。

2.深拷贝

深拷贝其实就是不仅将需要克隆的对象进行拷贝了,也将对象里面的对象也进行了重新的拷贝.

这只是简单举例,不论有多少个对象,都会进行一一的进行拷贝处理,这种方法就叫做深拷贝.

接下来是网络上的定义:

深拷贝则是指复制了对象本身,而不仅仅是对象的引用。因此,新对象和原对象在内存中拥有不同的地址,彼此之间没有任何关联。深拷贝通常能够完全复制原对象,包括所有的属性和引用对象,因此比浅拷贝更加安全和可靠。

3.实现深拷贝的两种方法

1.一种是递归的进行拷贝

具体应该将Person类中的clone()方法进行如下的修改

    @Override
    public Person clone() throws CloneNotSupportedException {
        Person person=(Person) super.clone();
        Dog dog1 = person.dog.clone();
        person.dog=dog1;
        return person;
    }

但是这种方法已经是很老旧的方法了,现在计算机实现已经不采用了这种方法了,现在使用的深拷贝方法是第二种方法.

2.Json字符串的方式进行深拷贝

使用JSON字符串进行深拷贝需要以下步骤:

1.将对象转换为JSON字符串:使用JSON库,如Jackson、Gson或FastJSON,将需要拷贝的对象转换为JSON字符串。

2.将JSON字符串转换回对象:使用JSON库将JSON字符串转换回一个新的对象。

这将创建一个新的对象,其属性与原始对象相同,但是它们不会共享对象引用,而是创建新的引用。

下面是一个使用Jackson库进行深拷贝的示例代码:

import com.fasterxml.jackson.databind.ObjectMapper;

public class DeepCopyUtils {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static <T> T deepCopy(T object) throws Exception {
        String jsonString = objectMapper.writeValueAsString(object);
        return objectMapper.readValue(jsonString, (Class<T>) object.getClass());
    }
}

在这个示例代码中,我们使用Jackson的ObjectMapper类将对象转换为JSON字符串,并将其转换回新的对象。

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

允歆辰丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值