浅谈java的深浅拷贝

本文通过具体示例讲解了Java中深拷贝与浅拷贝的区别,展示了如何实现这两种拷贝方式,并通过运行结果直观地说明了它们的不同之处。
 
首先,先介绍一下java中的深拷贝以及浅拷贝,深浅拷贝都属于克隆,不同的是浅拷贝是指只对对象的基本类型进行一个简单的拷贝,而深拷贝是指对对象的所有属性进行拷贝,不论是基本类型还是引用类型。
为了让大家更深刻了解深浅拷贝,下面举例说明:
class CloneTest
{
        
         public static void main(String[] args)
         {
                  
                   Manager m=new Manager("manager",50);
                   Programmer p1=new Programmer("tomison",18,m);
                   Programmer p2=(Programmer)st1.clone();
                   p2.name="jason";
                   p2.aa[0] = 10;
                   p2.m.name = "projectManager";
                   System.out.println(p1.name+"   "+p2.name);
                   System.out.println(p1.m.name+"   "+p2.m.name);
                   System.out.println(p1.aa[0]+"   "+p2.aa[0]);
                  
         }       
}
//要想对一个对象实现拷贝功能,必须实现Cloneable,重写clone()方法
class Manager implements Cloneable
{
         String name;
         int age;
         Manager(String name,int age)
         {
                   this.name=name;
                   this.age=age;
         }       
         public Object clone()
         {
                   Object o=null;
                   try
                   {
                            o=super.clone();
                   }
                   catch(CloneNotSupportedException e)
                   {
                            System.out.println(toString());
                   }                
                   return o;
         }                
}       
class Programmer implements Cloneable
{
         String name;
         int age;
         Manager m;
         int[] aa = new int[3];
         Programmer(String name,int age,Manager m)
         {
                   this.name= new String(name);
                   this.age=age;
                   this.m=m;
                   this.aa[0]=1;
                   this.aa[1]=2;
                   this.aa[2]=3;
         }
         public Object clone()
         {
                   Programmer o=null;
                   try
                   {
                            o=(Programmer)super.clone();
                   }
                   catch(CloneNotSupportedException e)
                   {
                            System.out.println(toString());
                   }       
                   //o.m=(Manager)o.m.clone();         
                   //o.aa = (int[])o.aa.clone();
                   return o;
         }                
}
 
上面的运行结果如下:
tomison     Jason
projectManager    projectManager
10    10
从上面可以看出,Programmer类p1中的引用类型Manager以及数组aa随着p2值的改变而改变,基本类型name没有随着p2值的改变而改变,因为Programmer类只实现了浅拷贝,p1、p2引用类型属性的值指向的都是同一个内存地址,所以当p2中的引用属性的值更改时,相应p1的值也会更改,把以下两行注释去掉,看看运行的结果有何不同:
o.m=(Manager)o.m.clone();   
o.aa = (int[])o.aa.clone();
这时的运行结果如下:
tomison     Jason
manager    projectManager
1    10
 
当去掉那两行注释后,Programmer这个类除了对基本类型进行一个拷贝之外,还分别对引用类型进行拷贝,从而实现了深拷贝,因此p2的值更改时不会影响p1的值,在这里要特别注意的是数组也是属于引用类型的一种。
### 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]。 #### 总结 - **浅拷贝**只涉及基础属性的直接赋值以及简单引用指针的传递;当涉及到复合型或多层次的数据结构时容易出现问题。 - **深拷贝**则完全隔离源目标及其子组件间的联系,从而避免不必要的干扰风险。但是它的代价相对较高,尤其是在面对庞大且错综复杂的数据集时更是如此。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值