JavaDog程序狗
JavaDog程序狗
发布于 2025-05-18 / 8 阅读
0
0

【Java】小老弟,别再被Java深拷贝浅拷贝绕晕啦

前言

🐟缘由

Java对象拷贝:双胞胎还是影分身?深浅拷贝大揭秘!

想象一下,你和你的双胞胎兄弟共享同一套玩具,结果他把玩具车撞坏了,你瞬间心疼到怀疑人生——这就是浅拷贝的日常!而如果你们各自拥有独立的玩具仓库,那就是深拷贝的境界了。

今天,咱们就化身“克隆专家”,用双胞胎理论+影分身实战,彻底搞懂Java对象拷贝的那些事儿!保证看完后,再也不怕面试官问“深浅拷贝区别”!


🐣闪亮主角

一文搞懂Java对象深拷贝与浅拷贝

大家好,我是JavaDog程序狗

今天我要像《X战警》里的“复制猫”一样,带你揭开对象拷贝的神秘面纱!从双胞胎共享玩具独立仓库影分身,咱们一个不落!


正文

🎯主要目标

1. 什么是对象拷贝?

2. 浅拷贝 vs 深拷贝:双胞胎 vs 影分身

3. 浅拷贝的致命陷阱:共享对象的“连环爆炸”

4. 深拷贝的正确姿势:如何实现真正的“独立王国”

5. 代码实战:用玩具车和仓库演示深浅拷贝


🍪目标讲解

一. 对象拷贝:为什么需要克隆?

1. 白话理解

对象拷贝就像克隆一只宠物仓鼠。假设你有一只叫“小肥”的仓鼠,你想再“克隆”一只“小瘦”,但有两种玩法:

  • 浅拷贝:小肥和小瘦共享同一个食盆,你给小肥加餐,小瘦也跟着饱了。
  • 深拷贝:小肥和小瘦各自拥有独立的食盆,你喂谁都是喂自己。

2. 技术定义

对象拷贝是创建对象副本的过程。在Java中,拷贝分为浅拷贝深拷贝,区别在于是否复制对象内部的引用类型成员。


二. 浅拷贝:双胞胎的“共享人生”

1. 浅拷贝的实现

// 浅拷贝实现:通过Cloneable接口
public class Person implements Cloneable {
    private String name;
    private Car car; // 引用类型
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // 只拷贝基本类型和引用地址
    }
}

2. 浅拷贝的致命问题

Person p1 = new Person("小明", new Car("Tesla"));
Person p2 = (Person) p1.clone();
p2.getCar().setBrand("比亚迪"); // 此时p1的car品牌也被改了!

问题p1p2共享同一个Car对象,修改其中一个的引用对象会直接影响另一个!


三. 深拷贝:影分身的“独立王国”

1. 深拷贝的实现方式

方式一:序列化克隆

public class DeepCopyUtil {
    public static <T extends Serializable> T deepCopy(T obj) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return (T) ois.readObject();
        } catch (Exception e) {
            throw new RuntimeException("深拷贝失败", e);
        }
    }
}

方式二:手动递归拷贝

public class Person implements Cloneable {
    private String name;
    private Car car;
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person clone = (Person) super.clone();
        clone.car = new Car(this.car.getBrand()); // 手动拷贝引用对象
        return clone;
    }
}

2. 深拷贝的优势

Person p1 = new Person("小明", new Car("Tesla"));
Person p2 = DeepCopyUtil.deepCopy(p1);
p2.getCar().setBrand("比亚迪"); // p1的car品牌保持不变!

四. 浅拷贝 vs 深拷贝:一场关于“独立”的辩论

特性 浅拷贝 深拷贝
拷贝内容 基本类型 + 引用地址 基本类型 + 引用对象的独立副本
性能 高(只拷贝地址) 低(需递归拷贝所有对象)
适用场景 临时拷贝、性能敏感场景 数据隔离、修改不互相影响的场景
实现难度 低(实现Cloneable) 高(需序列化或手动递归)

五. 代码实战:用玩具车和仓库演示深浅拷贝

1. 场景:玩具店的“克隆风波”

class ToyCar {
    private String brand;
    private List<String> stickers; // 引用类型
    
    // 省略getter/setter
}

class ToyStore {
    private ToyCar bestSeller;
    
    // 浅拷贝方法
    public ToyStore shallowCopy() {
        ToyStore copy = new ToyStore();
        copy.bestSeller = this.bestSeller; // 共享同一个ToyCar对象!
        return copy;
    }
    
    // 深拷贝方法(递归拷贝)
    public ToyStore deepCopy() {
        ToyStore copy = new ToyStore();
        copy.bestSeller = new ToyCar();
        copy.bestSeller.setBrand(this.bestSeller.getBrand());
        copy.bestSeller.setStickers(new ArrayList<>(this.bestSeller.getStickers()));
        return copy;
    }
}

2. 实验结果

ToyStore store1 = new ToyStore(new ToyCar("乐高", Arrays.asList("闪电贴纸")));
ToyStore store2 = store1.shallowCopy();
store2.getBestSeller().getStickers().add("新贴纸"); // store1的贴纸也被修改了!

ToyStore store3 = store1.deepCopy();
store3.getBestSeller().setBrand("芭比"); // store1的品牌保持不变!

总结

Java对象拷贝分为浅拷贝和深拷贝

浅拷贝仅复制对象的基本字段和引用地址,不复制引用对象本身,导致新旧对象共享引用类型数据(如修改car属性时两者同步变化)。其通过Cloneable接口实现,性能高但存在“共享修改”风险,适合临时拷贝或性能敏感场景。

深拷贝则复制对象及所有嵌套对象的独立副本,新旧对象完全隔离(修改深拷贝对象不影响原对象)。其实现方式包括序列化反序列化或手动递归拷贝,适用于需数据隔离的场景,但性能较低。

🍈猜你想问

如何与博主联系进行探讨

关注公众号【JavaDog程序狗】

公众号回复【入群】或者【加入】,便可成为【程序员学习交流摸鱼群】的一员,问题随便问,牛逼随便吹,目前群内已有超过380+个小伙伴啦!!!

2. 踩踩博主博客

javadog.net

里面有博主的私密联系方式呦 !,大家可以在里面留言,随意发挥,有问必答😘

🍯猜你喜欢

文章推荐

【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)

【规范】看看人家Git提交描述,那叫一个规矩

【项目实战】SpringBoot+uniapp+uview2打造H5+小程序+APP入门学习的聊天小项目

【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序

【模块分层】还不会SpringBoot项目模块分层?来这手把手教你!


评论