java深浅拷贝(复制)

本文详细解释了Java中深拷贝与浅拷贝的概念及其区别,并提供了通过序列化实现深拷贝的具体代码实例。

java深浅拷贝(复制)

分类: java基础 50人阅读 评论(0) 收藏 举报
 

首先我们看看浅拷贝和深拷贝的定义

浅拷贝:只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制

深拷贝:对象,对象内部的引用均复制

为了更好的理解它们的区别我们假设有一个对象A,它包含有2对象对象A1和对象A2(图1)


 

对象A进行浅拷贝后,得到对象B但是对象A1和A2并没有被拷贝(图2)


 

对象A进行深拷贝,得到对象B的同时A1和A2连同它们的引用也被拷贝(图3)


 

在理解了深拷贝和浅拷贝后,我们来看看java的深拷贝和浅拷贝实现。java.lang.Object的clone()方法默认是返回一个前拷贝对象。因此如果要用clone()方法实现一个深拷贝,我们必须对每个对象的clone()方法进行特别实现。当对象层次复杂的时候,这样做不但困难而且浪费时间和容易出现错误,特别有时候你不但需要深拷贝同时你也对这个对象进行浅拷贝的时候,你会发现写这个clone()方法真不是一个好的解决方案。

 

那么除了clone()方法,我们还可以怎么实现呢?答案是序列化,实现步骤和思路是把要拷贝的对象输出成byte array,然后再利用ObjectInputStream转换出新的对象。下面是代码

public static Object copy(Object oldObj) {  

    Object obj = null;  

    try {  

        // Write the object out to a byte array  

        ByteArrayOutputStream bos = new ByteArrayOutputStream();  

        ObjectOutputStream out = new ObjectOutputStream(bos);  

        out.writeObject(oldObj);  

        out.flush();  

        out.close();  

        // Retrieve an input stream from the byte array and read  

        // a copy of the object back in.  

        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());   

        ObjectInputStream in = new ObjectInputStream(bis);  

        obj = in.readObject();  

    } catch (IOException e) {  

        e.printStackTrace();  

    } catch (ClassNotFoundException cnfe) {  

        cnfe.printStackTrace();  

    }  

    return obj;  

### Java 深拷贝与浅拷贝的概念及实现 #### 浅拷贝 (Shallow Copy) 浅拷贝是指创建一个新的对象,这个新对象会复制原对象中的基本数据类型字段的值。而对于引用类型的字段,则仅仅复制其引用地址而不是实际的对象内容。这意味着如果原始对象和副本对象中存在相同的引用类型成员变量,在修改其中一个对象的内容时,另一个对象也会受到影响。 在 Java 中可以通过 `Object` 类的 `clone()` 方法来实现浅拷贝,前提是该类实现了 `Cloneable` 接口[^1]。下面是一个简单的例子展示如何通过重写 `clone()` 方法来进行浅拷贝: ```java class Person implements Cloneable { String name; int age; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class Main { public static void main(String[] args) throws CloneNotSupportedException { Person original = new Person(); original.name = "John"; original.age = 30; Person copiedPerson = (Person) original.clone(); System.out.println(copiedPerson.name); // 输出 John System.out.println(copiedPerson.age); // 输出 30 } } ``` 需要注意的是,上述代码仅适用于不包含任何引用类型的情况。如果有嵌套对象,则这些对象不会被克隆,而是共享同一个实例[^2]。 #### 深拷贝 (Deep Copy) 深拷贝不仅复制了对象本身,还对其内部所有的引用类型也进行了独立的复制操作。因此即使两个对象之间有相同的数据结构层次关系,它们也不会相互影响。要完成一次完整的深拷贝通常需要手动编写逻辑或者利用序列化机制自动处理复杂的对象图谱。 一种常见的方式是借助于 Java 的序列化功能实现深拷贝。具体做法如下所示: ```java import java.io.*; class Address implements Serializable { private String city; public Address(String city) { this.city = city; } public String getCity() {return city;} public void setCity(String city){this.city=city;} } class Employee implements Serializable, Cloneable{ private String name; private transient Address address; public Employee(String name, Address address){ this.name=name; this.address=address; } public String getName(){return name;} public void setName(String name){this.name=name;} public Address getAddress(){return address;} public void setAddress(Address address){this.address=address;} public Employee deepCopy() throws IOException, ClassNotFoundException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (Employee)ois.readObject(); } } public class DeepCopyExample { public static void main(String []args)throws Exception{ Address addr=new Address("New York"); Employee emp=new Employee("Tom",addr); Employee clonedEmp=(Employee)emp.deepCopy(); System.out.println(emp.getAddress().getCity()); // New York System.out.println(clonedEmp.getAddress().getCity());// null because 'transient' keyword prevents serialization of the field. } } ``` 在这个例子中可以看到,虽然我们尝试对整个员工对象执行了一次深拷贝,但由于 `Address` 成员标记为 `transient` ,所以它并没有参与序列化的流程,最终导致复制后的对象丢失了一些信息[^3]。 #### 总结 - **浅拷贝**只涉及基础属性的直接赋值以及简单引用指针的传递;当涉及到复合型或多层次的数据结构时容易出现问题。 - **深拷贝**则完全隔离源目标及其子组件间的联系,从而避免不必要的干扰风险。但是它的代价相对较高,尤其是在面对庞大且错综复杂的数据集时更是如此。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值