Java中浅拷贝与深拷贝实例解析

 更新时间:2023年09月04日 08:29:46   作者:DS程序员  
这篇文章主要给大家介绍了关于Java中浅拷贝与深拷贝的相关资料,拷贝对象是java中经常会遇到的问题,文中通过代码示例介绍的非常详细,需要的朋友可以参考下

前言

在Java中,对象的拷贝有两种方式:浅拷贝和深拷贝。它们分别代表了不同的拷贝方式,拷贝出的新对象与原始对象之间存在一定的差异。本文将详细介绍浅拷贝和深拷贝的概念、特点和实现方式,并且通过实例进行解析。

一、浅拷贝 

浅拷贝是指在对一个对象进行拷贝时,只拷贝对象本身和其中的基本数据类型,而不拷贝对象内部的引用类型。因此,在浅拷贝的对象中,引用类型的变量指向的依旧是原始对象中的引用。

在Java中,实现浅拷贝可以使用Object类的clone()方法,或者手动重写类的clone()方法。下面是一个示例:

class Person implements Cloneable {
    private String name;
    private Address address;
    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Address {
    private String city;
    public Address(String city) {
        this.city = city;
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Address address = new Address("Beijing");
        Person person1 = new Person("Tom", address);
        Person person2 = (Person) person1.clone();
        System.out.println(person1 == person2); // false
        System.out.println(person1.getAddress() == person2.getAddress()); // true
    }
}

在上述代码中,我们定义了一个Person类和Address类。Person类中包含一个引用类型的成员变量address。使用Object类的clone()方法进行拷贝,并且在Person类中实现了Cloneable接口,并重写了clone()方法,使得Person类可以进行拷贝。

在main函数中,我们创建了一个Person对象person1,其中包含一个Address对象。接着,我们使用person1的clone()方法创建了一个新的Person对象person2,并使用“==”判断person1和person2是否是同一对象。结果为false,证明两个对象是不同的。接下来,我们使用“==”判断person1和person2中的address是否是同一对象,结果为true,即两个对象的address成员变量指向的是同一个地址。

总的来说,浅拷贝只是将原始对象的引用类型成员变量复制到新的对象中,因此新对象中的引用类型成员变量与原始对象中的成员变量指向同一对象。如果原始对象中的引用类型成员变量发生变化,新对象中的引用类型成员变量也会随之变化。

二、深拷贝 

深拷贝是指在对一个对象进行拷贝时,不仅拷贝对象本身和其中的基本数据类型,同时也拷贝对象内部的引用类型。因此,在深拷贝的对象中,引用类型的变量指向的是全新的对象。

在Java中,实现深拷贝的方式比较多,可以使用对象的序列化、手动编写clone()方法等。下面是一个使用对象序列化来实现深拷贝的例子:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Test {
    public static void main(String[] args) throws Exception {
        Address address = new Address("Beijing");
        Person person1 = new Person("Tom", address);
        Person person2 = (Person) deepCopy(person1);
        System.out.println(person1 == person2); // false
        System.out.println(person1.getAddress() == person2.getAddress()); // false
    }
    private static Object deepCopy(Object obj) throws Exception {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }
}
class Person implements Serializable {
    private String name;
    private Address address;
     public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }
    public Address getAddress() {
        return address;
    }
}
class Address implements Serializable {
    private String city;
     public Address(String city) {
        this.city = city;
    }
}

在上述代码中,我们定义了一个Person类和Address类,并且让它们都实现了Serializable接口。在main函数中,我们创建了一个Person对象person1,其中包含一个Address对象。接着,我们使用deepCopy()方法创建了一个新的Person对象person2,并使用“==”判断person1和person2是否是同一对象。结果为false,证明两个对象是不同的。接下来,我们使用“==”判断person1和person2中的address是否是同一对象,结果为false,即两个对象的address成员变量指向的是不同的地址。

在上述代码中,我们使用了一个deepCopy()方法来实现对象的深拷贝。该方法使用对象的序列化和反序列化来实现深拷贝。首先,将原始对象序列化成字节数组,然后再将字节数组反序列化成新的对象。这样可以保证复制出的新对象与原始对象完全独立,不会相互影响。

总结: 

浅拷贝和深拷贝是Java中常用的两种对象拷贝方式。浅拷贝只会复制对象内部的基本数据类型和引用类型变量的引用,而深拷贝会将对象内部所有的基本类型和引用类型都复制一份。使用clone()方法和重写clone()方法可以实现浅拷贝,使用对象序列化或手动复制可以实现深拷贝。在实现对象拷贝时需要根据具体情况选择合适的拷贝方式,以保证复制出的新对象能够满足应用需求。

到此这篇关于Java中浅拷贝与深拷贝的文章就介绍到这了,更多相关Java浅拷贝与深拷贝内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java日志API管理最佳实践详解

    Java日志API管理最佳实践详解

    这篇文章主要介绍了Java日志API管理最佳实践详解,记录日志只是有效地利用日志的第一步,更重要的是如何对程序运行时产生的日志进行处理和分析。,需要的朋友可以参考下
    2019-06-06
  • 20秒教你学会java List函数排序操作示例

    20秒教你学会java List函数排序操作示例

    这篇文章主要为大家介绍了20秒教你学会List函数排序操作示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Java中的定时任务调度Quartz举例详解

    Java中的定时任务调度Quartz举例详解

    这篇文章主要介绍了Java中的定时任务调度Quartz的相关资料,Quartz是Java平台上的一个强大且灵活的任务调度库,广泛应用于企业级应用中,本文介绍了Quartz的基本概念、核心组件、使用步骤和示例,帮助你更好地利用Quartz进行定时任务调度,需要的朋友可以参考下
    2024-12-12
  • 简单实现Java验证码功能

    简单实现Java验证码功能

    这篇文章主要为大家详细介绍了简单实现Java验证码功能的代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • 如何利用Jackson序列化忽略指定类型的属性详解

    如何利用Jackson序列化忽略指定类型的属性详解

    这篇文章主要给大家介绍了关于如何利用Jackson序列化忽略指定类型的属性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-11-11
  • Java 超详细带你掌握矩阵的运算

    Java 超详细带你掌握矩阵的运算

    在学习机器学习算法时,发现运用java 来实现有些算法代码时,会有很大困难,其中有一点就是 java 本身并没有矩阵运算的 api,所以进行要实现矩阵运算就尤其复杂,让我们一起了解矩阵的运算
    2022-03-03
  • java数据类型转换之自动类型转换和强制类型转换详解

    java数据类型转换之自动类型转换和强制类型转换详解

    在 Java 中,数据类型转换用于将一种基本数据类型的值转换为另一种基本数据类型,主要分为自动类型转换(隐式转换) 和强制类型转换(显式转换) 两种,下面小编就为大家简单介绍一下吧
    2025-11-11
  • RabbitMQ在微服务架构中的落地:消息推送 / 解耦 / 削峰填谷

    RabbitMQ在微服务架构中的落地:消息推送 / 解耦 / 削峰填谷

    本文介绍了RabbitMQ在微服务架构中的三大应用场景:消息推送、服务解耦和削峰填谷,通过实际代码示例展示了如何在实际项目中应用RabbitMQ实现这些模式,感兴趣的朋友一起看看吧
    2026-05-05
  • Java替换视频背景音乐的实现示例

    Java替换视频背景音乐的实现示例

    FFmpeg 是一个强大的开源多媒体处理工具,被广泛应用于音视频的录制、转码、编辑等方面,本文主要介绍了Java替换视频背景音乐,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • Java后台生成图片的完整步骤

    Java后台生成图片的完整步骤

    在一些详情页面中,可能需要对上传到服务器中的图片生成以缩略图的形式展示,这篇文章主要给大家介绍了关于Java后台生成图片的相关资料,需要的朋友可以参考下
    2021-08-08

最新评论