java深拷贝和浅拷贝

1、概念

java里的clone分为: 
A:浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 
b:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍。 
Java中对象的克隆,为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。必须要遵循下面三点 
1.在派生类中覆盖基类的clone()方法,并声明为public【Object类中的clone()方法为protected的】。 
2.在派生类的clone()方法中,调用super.clone()。 
3.在派生类中实现Cloneable接口。

注明:Object类里的clone方法是浅复制(浅克隆)

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 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);
    }
} 

那应该如何实现深层次的克隆,即修改s2的教授不会影响s1的教授?代码改进如下。 
改进使学生1的Professor不改变(深层次的克隆)

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);
    }
}

 参考:http://www.jb51.net/article/62909.html

时间: 2024-10-01 03:33:27

java深拷贝和浅拷贝的相关文章

java 深拷贝与浅拷贝机制详解

 java 深拷贝与浅拷贝机制详解            --摘自-https://www.jb51.net/article/106088.htm 概要: 在Java中,拷贝分为深拷贝和浅拷贝两种.java在公共超类Object中实现了一种叫做clone的方法,这种方法clone出来的新对象为浅拷贝,而通过自己定义的clone方法为深拷贝. (一)Object中clone方法 如果我们new出一个新对象,用一个声明去引用它,之后又用另一个声明去引用前一个声明,那么最后的结果是:这两个声明的变量将

Java深拷贝和浅拷贝(深克隆和浅克隆)

Java中创建对象有两种方式: 通过new操作符创建一个对象 通过clone方法来复制一个对象 使用反序列化来创建一个对象 通过使用Class类的newInstance方法来创建一个对象 使用Constructor类的newInstance方法来创建一个对象 第一种方法,通过new操作符来创建一个对象,分配内存,调用构造函数来填充各个域,这是我们最熟悉的:第二种clone也是分配内存,分配的内存和被clone对象相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法

Java深拷贝与浅拷贝

一.创建对象的方式 1. new关键字,A a=new A(); 2. Constructor类的newInstance()方法,反射实现 3. Class类的newInstance()方法,内部还是调用Constructor类的newInstance()方法,反射实现 4. clone()方法,复制对象产生一个新对象 5. 序列化反序列化 二.引用拷贝 vs 对象拷贝 A a1=new A(); A a2=a1;  // a2和a1是同一个对象,内存地址相同,即引用相同 三.浅拷贝:值类型拷贝

一看就懂的,java深拷贝浅拷贝

前言 这两天,男票兴奋地通知我,我的博客终于有排名了,刚好是20000名,原来都是千里之外.我也比较兴奋,在这里谢谢每一个看到我文章的同学.O(∩_∩)O哈哈~,为什么有一种颁奖典礼的赶脚.真的啦,虽然我的博客写的都是比较浅显的基础知识,但是也是一字一字马上去的,有时候为了画图辅助说明,也是费很多时间的.O(∩_∩)O哈哈~,我写博客的目的,就是希望每一个看我博客的人,每看一篇文章都能不用费很多时间,把文章里面的东西弄懂.虽不是大牛,但是我会继续努力的. 话不多说,进入今天的主题吧.今天,依然要

Java中的深拷贝和浅拷贝 原型模式

1: Java中浅拷贝和深拷贝的定义:      浅拷贝:就是指两个对象共同拥有同一个值,一个对象改变了该值,也会影响到另一个对象.      深拷贝:就是两个对象的值相等,但是互相独立. (深拷贝才是真正的拷贝,浅拷贝只是将引用指向了同一份对象) 2:Java中几种常见的拷贝操作: (1)"="操作:也就是赋值操作: (2)拷贝构造函数:拷贝构造函数就是构造函数的参数的类型是该构造函数所在的类,即参数就是该类的一个对象. <span style="font-size:

浅谈Java中的深拷贝和浅拷贝

浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: [java] view plaincopyprint? int apples = 5; int pears = apples; int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float

Java基础之浅拷贝与深拷贝

含义 浅拷贝:进对对象本身(包括对象中的基本变量)进行拷贝,而不拷贝对象包含的引用指向的对象. 深拷贝:不仅对对象本身,而且还对对象所包含的引用指向的对象进行拷贝. 深拷贝可以看做是对浅拷贝的递归. 举例来说:对象A1中包含对B1的引用,B1中包含对C1的引用.浅拷贝A1得到A2,A2 中依然包含对B1的引用,B1中依然包含对C1的引用.深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2 中包含对C2(C1的copy)的引用. 克隆方法clone() p

java中的深拷贝与浅拷贝

Java中对象的创建 clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象.那么在java语言中,有几种方式可以创建对象呢? 1 使用new操作符创建一个对象 2 使用clone方法复制一个对象 那么这两种方式有什么相同和不同呢? new操作符的本意是分配内存.程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间.分配完内存

JAVA中对象的克隆及深拷贝和浅拷贝

使用场景: 在日常的编程过程 中,经常会遇到,有一个对象OA,在某一时间点OA中已经包含了一些有效值 ,此时可能会需一个和OA完全相对的新对象OB,并且要在后面的操作中对OB的任何改动都不会影响到OA的值,也就是OA与Ob是需要完全两个独立的对象. 但OB的初始值是由对象OA确定的.在JAVA语言中,用普通的赋值语句是满足不了需求的.使用对象的clone()方法是实现克隆的最简单.也是最高效的手段. Java的所有类都默认继承java.lang.Object类,在java.lang.Object