Java基础-引用拷贝、浅拷贝、深拷贝

本文详细解释了Java中的引用拷贝、浅拷贝(通过Cloneable接口实现,仅复制引用)和深拷贝(包括对象和其内部对象),以及如何通过序列化方法实现更简洁的深拷贝。
摘要由CSDN通过智能技术生成
一、概念

引用拷贝:直接复制对象的引用。如下代码,copy是ex对象的引用拷贝,那么copy和ex是同一个引用,指向的也是同一个对象,那么自然拷贝对象和原对象的属性也是同一个。

@Data
public Class Example {

    private String str;


    public static void main() {
    
        Example ex = new Example;
        Example copy = ex;
        System.out.println(ex == copy); // true
        System.out.println(ex.str == copy.str); // true
    }
}

浅拷贝:浅拷贝可以通过实现Coleable接口实现。浅拷贝会创建一个新对象,但是对象内的属性需要注意:

(1) 对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据;

(2)对于数据类型是引用数据类型的成员变量,比如说成员变量是某个字符串、数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

@Date
@AllArgsConstructor
public class Example implements Cloneable {
    
    private int a;

    private String b;

    
    @Override
    public Example clone() {
        try {
            return (Example) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }


    public static void main() {
        
        Example ex = new Example(1, "old_data");
        Example copy = ex.clone();  // 浅拷贝

        System.out.println(ex == copy) // false 因为对象拷贝会创建一个新的对象
        System.out.println(ex.getB() == copy.getB()) // true 对象类型的成员属性传递的对象的引用

        ex.setA(10);
        System.out.println(ex.getA()); //10 
        System.out.println(copy.getA()); // 1 浅拷贝原始类型复制一份新数据给新的对象,不互相影响

        
        ex.setB("new_data");
        System.out.println(ex.getB()); // new_data 
        System.out.println(copy.getB()); // new_data 浅拷贝引用类型,就是原对象的成员变量的引用
    
    }
}

深拷贝:深拷贝不仅会创建一个新的对象,对象中的对象类型的成员属性也会创建一个新的,而不是引用原对象的成员。可改写一下浅拷贝中重写的clone()方法即可实现。

@Data
public class AnotherClass implements Cloneable {

    private String str;

    @Override
    public AnotherClass clone() {
        return (AnotherClass) super.clone();
    }
}

@Data
public class Example implements Cloneable {
    
    private int a;

    private AnotherClass b;

    public Example(int a, String str) {
        this.a = a;
        this.b.setStr(str);

    }

    public void setStr(String str) {
        this.b.setStr(str);
    }

    
    @Override
    public Example clone() {
        try {
            Example ret = (Example) super.clone();
            ret.setB(this.b.clone());
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }


    public static void main() {
        
        Example ex = new Example(1, "old_data");
        Example copy = ex.clone();  // 深拷贝

        System.out.println(ex == copy) // false 因为对象拷贝会创建一个新的对象
        System.out.println(ex.getB() == copy.getB()) // false 对象类型的成员变量也是一个新对象

        ex.setA(10);
        System.out.println(ex.getA()); //10 
        System.out.println(copy.getA()); // 1 浅拷贝原始类型复制一份新数据给新的对象,不互相影响

        
        ex.setStr("new_data");
        System.out.println(ex.getB().getStr()); // new_data 
        System.out.println(copy.getB().getStr()); // old_data 深拷贝引用类型是一个新的对象
    
    }
}

补充说明:上述通过重写clone()方法实现深拷贝的方式需要成员对象也去实现cloneable接口,特别对于属性数量比较多、层次比较深的类而言,每个类都要重写clone方法太过繁琐。更好的实现方式是对象序列化实现

@Data
@AllArgsConstructor
public class Example implements Serializable {

    private int a;

    private String b;

    public static void main(String[] args) {
        Example ex = new Example(1, "old_data");
        //通过序列化方法实现深拷贝
        ByteArrayOutputStream bos=new ByteArrayOutputStream();
        ObjectOutputStream oos= null;
        try {
            oos = new ObjectOutputStream(bos);
            oos.writeObject(ex);
            oos.flush();
            ObjectInputStream ois=new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
            Example copy = (Example) ois.readObject();
            copy.setB("new_data");
            System.out.println("ex.getB():" + ex.getB()); // old_data
            System.out.println("copy.getB():" + copy.getB()); // new_data
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值