`

(转)Java中对象的深复制(深克隆)和浅复制(浅克隆)

    博客分类:
  • java
阅读更多
1.浅复制与深复制概念
⑴浅复制(浅克隆)
    被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
⑵深复制(深克隆)
    被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
2.Java的clone()方法
⑴clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:
①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象
②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样
③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
⑵Java中对象的克隆
①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。
②在派生类中覆盖基类的clone()方法,并声明为public。
③在派生类的clone()方法中,调用super.clone()。
④在派生类中实现Cloneable接口。
请看如下代码:
public  class Student implements Cloneable    
{    
     String name;    
    int age;    
     Student(String name,int age)    
     {    
        this.name=name;    
        this.age=age;    
     }    
    public Object clone()    
     {    
         Object o=null;    
        try    
         {    
         o=(Student)super.clone();//Object 中的clone()识别出你要复制的是哪一个对象。    
         }    
        catch(CloneNotSupportedException e)    
         {    
             System.out.println(e.toString());    
         }    
        return o;    
     }     
   
    public static void main(String[] args)    
     {    
       Student s1=new Student("zhangsan",18);    
       Student s2=(Student)s1.clone();    
       s2.name="lisi";    
       s2.age=20;    
      //修改学生2后,不影响学生1的值。
       System.out.println("name="+s1.name+","+"age="+s1.age); 
       System.out.println("name="+s2.name+","+"age="+s2.age);
    }
}   

说明:
①为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。
②继承自java.lang.Object类的clone()方法是浅复制。以下代码可以证明之。
class Professor    
{    
     String name;    
     int age;    
     Professor(String name,int age)    
     {    
        this.name=name;    
        this.age=age;    
     }    
}    
public class Student implements Cloneable    
{    
     String name;// 常量对象。    
     int age;    
     Professor p;// 学生1和学生2的引用值都是一样的。    
     Student(String name,int age,Professor p)    
     {    
        this.name=name;    
        this.age=age;    
        this.p=p;    
     }    
    public Object clone()    
     {    
         Student o=null;    
        try    
         {    
             o=(Student)super.clone();    
         }    
        catch(CloneNotSupportedException e)    
         {    
             System.out.println(e.toString());    
         }    
         o.p=(Professor)p.clone();    
        return o;    
     }      
    public static void main(String[] args)    
    {    
       Professor p=new Professor("wangwu",50);    
       Student s1=new Student("zhangsan",18,p);    
       Student s2=(Student)s1.clone();    
       s2.p.name="lisi";    
       s2.p.age=30;        
       System.out.println("name="+s1.p.name+","+"age="+s1.p.age);
       System.out.println("name="+s2.p.name+","+"age="+s2.p.age);
       //输出结果学生1和2的教授成为lisi,age为30。
       } 
}  

那应该如何实现深层次的克隆,即修改s2的教授不会影响s1的教授?代码改进如下。
改进使学生1的Professor不改变(深层次的克隆)
class Professor implements Cloneable    
{    
     String name;    
     int age;    
     Professor(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(e.toString());    
         }    
        return o;    
     }    
}    
public class Student implements Cloneable    
{    
     String name;    
     int age;    
     Professor p;    
     Student(String name,int age,Professor p)    
     {    
        this.name=name;    
        this.age=age;    
        this.p=p;    
     }    
    public Object clone()    
     {    
         Student o=null;    
        try    
         {    
             o=(Student)super.clone();    
         }    
        catch(CloneNotSupportedException e)    
         {    
             System.out.println(e.toString());    
         }    
         //对引用的对象也进行复制
         o.p=(Professor)p.clone();    
        return o;    
     }      
    public static void main(String[] args)    
     {    
       Professor p=new Professor("wangwu",50);    
       Student s1=new Student("zhangsan",18,p);    
       Student s2=(Student)s1.clone();    
       s2.p.name="lisi";    
       s2.p.age=30;    
      //学生1的教授不 改变。
       System.out.println("name="+s1.p.name+","+"age="+s1.p.age);  
       System.out.println("name="+s2.p.name+","+"age="+s2.p.age);    
    }   
} 

3.利用串行化来做深复制(主要是为了避免重写比较复杂对象的深复制的clone()方法,也可以程序实现断点续传等等功能)
    把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做 “解冻”或者“回鲜(depicking)”过程。
    应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。
    在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。
如下为深复制源代码。
public Object deepClone()    
{    
   //将对象写到流里    
   ByteArrayOutoutStream bo=new ByteArrayOutputStream();    
   ObjectOutputStream oo=new ObjectOutputStream(bo);    
   oo.writeObject(this);    
   //从流里读出来    
   ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());    
   ObjectInputStream oi=new ObjectInputStream(bi);    
   return(oi.readObject());    
}   

    这样做的前提是对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象或属性可否设成transient,从而将之排除在复制过程之外。上例代码改进如下。
class Teacher implements Serializable{
     String name;
     int age;
     public void Teacher(String name,int age){
        this.name=name;
        this.age=age;
     }
}
public class Student implements Serializable{
    String name;//常量对象
    int age;
    Teacher t;//学生1和学生2的引用值都是一样的。
    public void Student(String name,int age,Teacher t){
       this.name=name;
       this.age=age;
       this.p=p;
    }
    public Object deepClone() throws IOException,
                OptionalDataException,ClassNotFoundException{//将对象写到流里
       ByteArrayOutoutStream bo=new ByteArrayOutputStream();
       ObjectOutputStream oo=new ObjectOutputStream(bo);
       oo.writeObject(this);//从流里读出来
       ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());
       ObjectInputStream oi=new ObjectInputStream(bi);
       return(oi.readObject());
    }
    public static void main(String[] args){ 
        Teacher t=new Teacher("tangliang",30);
        Student s1=new Student("zhangsan",18,t);
        Student s2=(Student)s1.deepClone();
        s2.t.name="tony";
        s2.t.age=40;
        //学生1的老师不改变
        System.out.println("name="+s1.t.name+","+"age="+s1.t.age);
    }
}
分享到:
评论

相关推荐

    java 深克隆浅克隆

    Java提供了两种主要的克隆方式:深克隆和浅克隆。 1. 浅克隆(Shallow Clone): 浅克隆是通过调用对象的`clone()`方法来实现的,这个方法是Object类提供的。当一个对象被浅克隆时,新创建的对象将拥有原始对象的...

    Java对象的深克隆与浅克隆详解.zip(wcb2003)

    总的来说,理解Java对象的深克隆和浅克隆是优化代码和解决特定问题的关键。根据具体需求选择合适的克隆方式,可以提高代码的可维护性和灵活性。在设计类和系统时,应考虑对象复制的需求,并决定是否实现`Cloneable`...

    java 深克隆 浅克隆

    在Java编程语言中,克隆是...理解深克隆和浅克隆的概念对于编写复杂的、性能敏感的Java程序至关重要,尤其是在处理大量对象或需要保持数据独立性时。根据具体需求选择合适的克隆策略,可以提高代码的灵活性和可维护性。

    java对象复制克隆

    标题中的“java对象复制克隆”主要涉及的是深拷贝,这是一种创建一个新对象的方式,新对象不仅复制了原对象的所有属性,还复制了嵌套的对象引用,使得修改复制后的对象不会影响到原始对象。 **浅拷贝**:在浅拷贝中...

    Java中对象的深复制和浅复制详解.doc

    对象复制分为两种主要类型:浅复制(浅克隆)和深复制(深克隆)。理解这两种复制方式的区别对于优化程序性能和避免意外数据更改至关重要。 1. **浅复制(浅克隆)** 浅复制是指创建一个新对象,该对象拥有原始...

    Java对象的复制克隆

    Java中的对象复制与克隆是程序开发中常见的需求,主要用于创建一个对象的副本,而不会影响原始对象的状态。这里主要讨论两种类型的对象拷贝:浅拷贝和深拷贝。 浅拷贝,也称为表面拷贝,是创建一个新的对象,然后将...

    android 浅复制和深复制-Java Generic Deep Copy 篇

    本文将深入探讨Java中的浅复制和深复制,并以Android为背景,结合具体的实例讲解如何实现Java泛型深拷贝。 首先,我们要理解浅复制和深复制的概念。浅复制(Shallow Copy)是指创建一个新的对象,然后将原对象引用...

    JAVA浅克隆与深克隆

    在Java中,深克隆通常通过序列化和反序列化来实现,或者手动创建一个新的对象并复制所有字段。下面是一个使用序列化实现深克隆的例子: ```java import java.io.*; // 在Student类中添加序列化和反序列化方法 ...

    java List 深度复制方法

    如果元素是不可变的(如String、Integer等包装类),那么浅复制和深复制并无太大差异,因为这些对象一旦创建就无法改变。但对于可变对象(如自定义类实例),我们需要通过序列化和反序列化,或者手动创建新对象并...

    浅拷贝(浅复制、浅克隆)、深拷贝(深复制、深克隆)实战工程

    在编程领域,尤其是在Java语言中,对象的复制是常见的操作,这涉及到两个主要概念:浅拷贝(浅复制、浅克隆)和深拷贝(深复制、深克隆)。这两个概念是理解对象生命周期和内存管理的关键部分。下面将详细阐述它们的...

    java不同对象及集合的多次复制

    在Java编程中,对象复制是一项常见的任务,特别是在处理模型(Model)和视图对象(VO)时。模型对象通常用于封装业务数据,而视图对象则用于展示这些数据。值复制,即对象属性值的复制,是保持数据一致性和简化代码...

    java不同对象之间及集合的复制

    在Java中,如果类的属性都是基本类型,可以通过构造函数或克隆方法实现浅复制。但如果属性包含引用类型,就需要深复制以确保新对象拥有独立的引用。 3. **注解实现复制**: 注解是一种元数据,可以提供编译时或运行...

    Java中对象的深复制(深克隆)和浅复制(浅克隆)介绍

    总结一下,Java中的对象复制分为两种主要类型: 1. **浅复制(浅克隆)**:只复制对象本身,不复制其引用的对象。如果对象中包含其他对象的引用,这些引用在复制后依然指向原来的对象。在上面的示例中,`Student`的...

    实例分析java对象中浅克隆和深克隆

    浅克隆和深克隆在Java对象中的应用 在Java编程语言中,克隆(Clone)是一种常见的对象复制机制。克隆可以分为浅克隆(Shallow Clone)和深克隆(Deep Clone)两种。浅克隆仅复制对象的引用,而深克隆则完全复制对象...

    java 对象克隆

    浅克隆创建的新对象只复制了原对象的引用,这意味着如果原对象中包含可变的引用类型,如数组或复杂的数据结构,那么新对象和原对象会共享这些引用。因此,对这些引用的修改会影响到两个对象。相反,深克隆不仅复制了...

    JAVA_对象克隆

    1. 浅克隆:默认的`clone()`方法执行的是浅克隆,它创建的新对象只复制原始对象的基本数据类型字段,对于引用类型的字段,新对象和原始对象共享同一个引用。这意味着对引用对象的修改会影响到原始对象。 2. 深克隆...

    java深复制浅复制的实现源代码

    在Java编程语言中,对象复制是一个常见的操作,特别是在处理数据持久化、克隆或并发控制时。本篇文章将深入探讨Java中的深复制和浅复制概念,并通过源代码示例进行详细解析。 首先,我们理解一下深复制和浅复制的...

    MyBatisDemo && JAVA把一个对象的全部属性复制到另一个相同的对象

    首先,我们要理解Java中的对象复制有浅拷贝和深拷贝两种方式。浅拷贝只复制对象本身,不复制引用的对象;深拷贝不仅复制对象,还复制对象中引用的对象。在描述中提到的方法,很可能是关于深拷贝的实现。 在Java中,...

    Java深复制与浅复制.doc

    在Java编程中,复制对象是常见的操作,主要分为两种方式:浅复制(Shallow Copy)和深复制(Deep Copy)。这两种复制方式的区别在于处理对象内部引用其他对象的情况。 1. **浅复制(浅克隆)**: 浅复制是指创建一...

Global site tag (gtag.js) - Google Analytics