JAVA引用传递、浅拷贝、深拷贝

本文深入探讨Java中对象拷贝的概念,通过具体示例解释浅拷贝与深拷贝的区别,包括引用传递、对象复制及序列化实现深拷贝的方法。

测试类:

Player类,包含name  level  和  weapon   三个成员


public class Player implements Cloneable {

    private static final long serialVersionUID = -75L;

    private String name;
    private int level;
    private Weapon weapon;

    public Player(){
        name = "sam";
        level = 10;
        weapon = new Weapon();
    }

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public String getName() {
        return name;
    }

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

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public Weapon getWeapon() {
        return weapon;
    }

    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }

    @Override
    public String toString() {
        return "Player{" +
                "name='" + name + '\'' +
                ", level=" + level +
                ", weapon=" + weapon.getName() +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Player o = (Player) super.clone();
        return o;
    }
}

 Weapon:包含 name 一个成员


public class Weapon implements Cloneable {

    private String name;

    public Weapon(String name) {
        this.name = name;
    }

    public Weapon() {
        this.name = "AK74";
    }

    public String getName() {
        return name;
    }

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

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

1.  直接赋值,引用传递,C2 = C1 ,不会为复制过去的实例分配空间,C2这个引用直接指向C1的实例,C1中有成员改变,C2也同样改变,很好理解。

这里r1赋值给r2,之后改变r1的成员,再次打印r2

        Player r1 = new Player();
        Player r2 = r1;

        r1.setName("tom");
        r1.setLevel(20);
        r1.getWeapon().setName("HK416");

        System.out.println(r2);

输出结果:可见r2的值已经随着r1更新。 

 

2.  浅拷贝,使用Object.clone()方法 ,C1复制到新实例中(堆上分配空间),C2指向这个新实例。

复制的过程中:如果字段是值类型的,那么对该字段执行复制。如果该字段是引用类型的话,则复制引用但不复制引用的对象。

首先Player和Weapon都已实现Cloneable接口的clone方法,执行clone,之后改变r1的成员,再次打印r2内容

 
        Player r1 = new Player();
        Player r2 = (Player) r1.clone();

        r1.setName("tom");
        r1.setLevel(20);
        r1.getWeapon().setName("HK416");

        System.out.println(r2);

输出结果:r2中,字段为值类型的部分则被复制成功,随着r1更新,并未变化。但weapon字段却更新为HK416了,说明r2中的weapon还是指向了r1的weapon

 
3.  深拷贝,同样使用Object.clone()方法 ,复制引用并同时复制引用的对象
 
重构Player中的clone方法,将引用类型成员也clone过去。
 
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Player o = (Player) super.clone();
        o.weapon = (Weapon) weapon.clone();
        return o;
    }

 输出结果:可见此时r2完全未受到r1成员变更的影响,通俗的理解,r2现在完全与r1脱离了。

4. 深拷贝的另一种实现:实现 Serializable接口,序列化,写入文件再读出,这个很好理解,读出来,是一个新的实例了,肯定是深拷贝。不再赘述。

### Java 深拷贝浅拷贝的概念 在Java中,当提到对象的拷贝时,通常会涉及到两种类型的拷贝:浅拷贝深拷贝浅拷贝指的是创建一个新的对象,这个新对象拥有原对象属性值的一个副本;如果这些属性是基本数据类型,则直接复制其值;如果是引用类型,则两个对象共享同一个引用指向同一地址空间的数据[^2]。 相比之下,深拷贝不仅复制了原始对象本身及其所有的成员变量(无论是基本数据类型还是引用类型),而且还会递归地为每一个被引用的对象也创建一份独立的新副本,从而使得源对象与其克隆体之间完全隔离,互不影响[^3]。 ### 浅拷贝的具体表现形式 对于实现了`Cloneable`接口并通过覆写`Object.clone()`方法来执行默认行为的情况,默认情况下只会做一层级的字段赋值操作——即只对当前类声明的那些域进行简单复制而不涉及任何子对象内部结构的变化。这意味着: - 基本数据类型的成员会被真正意义上的复制; - 对于数组或者复合对象而言,仅仅是把原来的引用传递给了新的实例而已,并未开辟额外的空间去保存另一份相同的内容[^1]。 ```java public class ShallowCopyExample implements Cloneable { private int value; private Object reference; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } ``` ### 实现深拷贝的方法 #### 方法一:构造函数 可以通过自定义构造器接收待复制的对象作为参数,在此过程中手动初始化各个组件以达到深层次上的分离效果。 ```java public class DeepCopyConstructorExample { private String name; private ArrayList<String> list; public DeepCopyConstructorExample(String name, List<String> originalList) { this.name = new String(name); // 复制字符串内容而非仅指针 this.list = new ArrayList<>(originalList); } // ... getter and setter methods ... } ``` #### 方法二:重载 `clone()` 方法 除了调用父类提供的公共API之外,还需要确保所有非基础类型的成员都被适当地处理过,例如通过循环遍历集合元素逐个调用各自对应的`.clone()`逻辑直至最底层为止。 ```java @Override protected Object clone() throws CloneNotSupportedException { DeepCopyCloneMethodExample clonedObj = (DeepCopyCloneMethodExample )super.clone(); // 手动复制可变部分 clonedObj.mutableField = mutableField.clone(); return clonedObj ; } ``` #### 方法三:利用序列化机制 借助Java内置的I/O流特性,先将目标实体转换成字节序列再反向解析回内存映像即可间接完成整个树状图谱下节点间关系重建的工作流程。 ```java // 序列化过程省略... ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(originalObject); // 反序列化恢复对象 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); DeepCopiedSerialized obj = (DeepCopiedSerialized)ois.readObject(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值