当前位置: 首页 > article >正文

【某大厂一面】java深拷贝和浅拷贝的区别

在 Java 中,深拷贝浅拷贝的主要区别在于对象的复制方式和对象中引用类型的处理。下面是更详细的解释,其中也会有相应的代码说明:

1. 浅拷贝(Shallow Copy)

浅拷贝是指复制一个对象时,复制的是对象的“结构”,但对于对象内部的引用类型的成员变量,它们的引用地址并不会被复制,而是共享同一引用。换句话说,浅拷贝只是创建了一个新的对象,但如果该对象内部含有引用类型的成员变量,这些成员变量还是指向原始对象中的相同内存地址。

浅拷贝的特点
  • 浅拷贝复制了对象本身,但并没有复制对象的引用类型成员。
  • 对于引用类型字段(如数组、集合、对象),它们的引用会被共享。
浅拷贝的实现方式
  1. 通过 clone() 方法:Java 的 Object 类提供了 clone() 方法来实现浅拷贝。
  2. 通过 copy() 方法:如果是 ArrayList 等集合类型,可以使用 ArrayListclone() 方法进行浅拷贝。
示例:
import java.util.ArrayList;

class Person implements Cloneable {
    String name;
    ArrayList<String> hobbies;

    public Person(String name, ArrayList<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

    // 重写 clone 方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();  // 浅拷贝
    }

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

public class ShallowCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        ArrayList<String> hobbies = new ArrayList<>();
        hobbies.add("Reading");
        hobbies.add("Swimming");

        Person person1 = new Person("John", hobbies);
        Person person2 = (Person) person1.clone(); // 浅拷贝

        // 修改 person2 的 hobbies
        person2.hobbies.add("Cooking");

        System.out.println("person1: " + person1);
        System.out.println("person2: " + person2);
    }
}

输出:

person1: Person{name='John', hobbies=[Reading, Swimming, Cooking]}
person2: Person{name='John', hobbies=[Reading, Swimming, Cooking]}

在这个示例中,person1person2hobbies 共享同一个引用,因此修改 person2 中的 hobbies 也会影响到 person1 中的 hobbies

2. 深拷贝(Deep Copy)

深拷贝是指复制一个对象及其内部的所有对象,包括所有引用类型的字段,确保它们有独立的内存空间。换句话说,深拷贝不仅复制了对象本身,还递归地复制对象中包含的每个引用类型的成员变量。这样,原对象和新对象之间就完全独立了,它们不会共享任何引用。

深拷贝的特点
  • 深拷贝会创建一个新的对象,并且递归地复制对象中引用类型的所有成员变量。
  • 原始对象和新对象完全独立,修改新对象不会影响原始对象。
深拷贝的实现方式
  1. 手动实现深拷贝:通过逐个复制对象中的引用类型成员变量来实现。
  2. 通过序列化和反序列化:可以利用 Java 的序列化机制来实现深拷贝,这种方式适用于对象较复杂的情况。
  3. 通过 clone() 方法的深度实现:需要在 clone() 方法中递归地克隆对象中的引用类型字段。
示例:
import java.util.ArrayList;

class Person implements Cloneable {
    String name;
    ArrayList<String> hobbies;

    public Person(String name, ArrayList<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

    // 实现深拷贝
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone(); // 浅拷贝
        // 进行深拷贝,创建一个新的 hobbies 列表
        cloned.hobbies = new ArrayList<>(this.hobbies);  // 深拷贝
        return cloned;
    }

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

public class DeepCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        ArrayList<String> hobbies = new ArrayList<>();
        hobbies.add("Reading");
        hobbies.add("Swimming");

        Person person1 = new Person("John", hobbies);
        Person person2 = (Person) person1.clone(); // 深拷贝

        // 修改 person2 的 hobbies
        person2.hobbies.add("Cooking");

        System.out.println("person1: " + person1);
        System.out.println("person2: " + person2);
    }
}

输出:

person1: Person{name='John', hobbies=[Reading, Swimming]}
person2: Person{name='John', hobbies=[Reading, Swimming, Cooking]}

在这个示例中,person1person2hobbies 列表是独立的,因此修改 person2hobbies 不会影响 person1

3. 使用序列化实现深拷贝(通过反序列化)

使用序列化和反序列化可以方便地进行深拷贝,前提是对象及其成员变量都需要实现 Serializable 接口。

示例(通过序列化实现深拷贝):
import java.io.*;

class Person implements Serializable {
    String name;
    ArrayList<String> hobbies;

    public Person(String name, ArrayList<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

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

public class DeepCopyBySerialization {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ArrayList<String> hobbies = new ArrayList<>();
        hobbies.add("Reading");
        hobbies.add("Swimming");

        Person person1 = new Person("John", hobbies);

        // 深拷贝:序列化 -> 反序列化
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bos);
        out.writeObject(person1);
        out.flush();
        byte[] byteData = bos.toByteArray();

        ByteArrayInputStream bis = new ByteArrayInputStream(byteData);
        ObjectInputStream in = new ObjectInputStream(bis);
        Person person2 = (Person) in.readObject();

        // 修改 person2 的 hobbies
        person2.hobbies.add("Cooking");

        System.out.println("person1: " + person1);
        System.out.println("person2: " + person2);
    }
}

输出:

person1: Person{name='John', hobbies=[Reading, Swimming]}
person2: Person{name='John', hobbies=[Reading, Swimming, Cooking]}

4. 总结

  • 浅拷贝:复制对象本身,但嵌套对象或引用类型的字段引用仍然指向原对象,即对象的引用被共享。
  • 深拷贝:不仅复制对象本身,还递归地复制所有引用类型的字段,确保原对象和新对象完全独立。

对于简单的对象,使用 clone() 方法实现浅拷贝即可。对于复杂的对象,或者需要独立对象时,可以手动实现深拷贝,或者使用序列化方式。

小伙伴们在开发的过程中有更好的代码实现或者具体的使用场景吗,欢迎大家在评论区进行讨论


http://www.kler.cn/a/523836.html

相关文章:

  • [C语言日寄] <stdio.h> 头文件功能介绍
  • 计算机网络 IP 网络层 2 (重置版)
  • 简要介绍C语言和c++的共有变量,以及c++特有的变量
  • Unity游戏(Assault空对地打击)开发(1) 创建项目和选择插件
  • 1.26学习
  • skynet 源码阅读 -- 核心概念服务 skynet_context
  • 顶刊JFR|ROLO-SLAM:首个针对不平坦路面的车载Lidar SLAM系统
  • 基于Python的智慧物业管理系统
  • aws sagemaker api 获取/删除 endpoints
  • ResNeSt: Split-Attention Networks论文学习笔记
  • MATLAB基础应用精讲-【数模应用】DBSCAN算法(附MATLAB、R语言和python代码实现)(二)
  • 54.数字翻译成字符串的可能性|Marscode AI刷题
  • Next.js 14 TS 中使用jwt 和 App Router 进行管理
  • 基于 NodeJs 一个后端接口的创建过程及其规范 -- 【elpis全栈项目】
  • oracle比较一下统计信息差异吧
  • Vue 响应式渲染 - 列表布局和v-html
  • 【2024年华为OD机试】(C卷,200分)- 推荐多样性 (JavaScriptJava PythonC/C++)
  • kaggle-ISIC 2024 - 使用 3D-TBP 检测皮肤癌-学习笔记
  • go 循环处理无限极数据
  • 【llm对话系统】大模型 RAG 之回答生成:融合检索信息,生成精准答案
  • HTML表单深度解析:GET 和 POST 提交方法
  • linux监控脚本+自动触发邮件发送
  • 【AI】【本地部署】OpenWebUI的升级并移植旧有用户信息
  • 面向对象编程 vs 面向过程编程
  • React第二十七章(Suspense)
  • mysql 学习5 mysql图形化界面DataGrip下载 安装 使用