A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 鲁中需 中级黑马   /  2012-10-25 10:29  /  1949 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

深拷贝与浅拷问题不是很清楚,希望用代码示例解释二者的区别用法。

评分

参与人数 1技术分 +1 收起 理由
韩军博 + 1 很给力!

查看全部评分

3 个回复

倒序浏览
本帖最后由 李连闯 于 2012-10-25 16:32 编辑

从基本的认识来看,浅拷贝与深拷贝的的区别在于是否对类(假设类名称是Book)的非静态引用变量(假设变量名称是person)的拷贝。
浅拷贝B类某个对象b1到b2,那么b1和b2持有的是相同的引用指向相同的对象,也就是b1对person的修改也会改变b2中的person,
而深拷贝的话则不会出现浅拷贝的情况,深拷贝情况下b1和b2是相互独立的,根本的区别其实就是Book类重写Object的clone方法(或者是其他的什么地方)时多加上person对象的复制编码person.clone()即可(如果Person类还有引用类型的变量,那么也需要调用该引用变量的clone方法,如果 ... ...)。
下面是改编的一份实例代码:
public class Person implements Cloneable{    //实现拷贝需要实现Cloneble借口,并重写Object的clone方法
   
    private String name;   
    private int age;   
    public Person(String name, int age) {      
        this.name = name;      
        this.age = age;   
    }   
   
    public String toString() {      
        return ("Name:" + name + ", Age:" + age);   
    }
     @Override
    public Object clone() {
         
        Person person = null;
        try {
            person = (Person) super.clone();
        }
        catch (CloneNotSupportedException e) {
             e.printStackTrace();
        }
         
        return person;
    }
     
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
----------------------------------------------------------
public class Book implements Cloneable{   
     
    private String bookName;        
    private Person author;   //这是主角
    //书籍和人相关联
    public Book(String bn,Person author){
        this.bookName = bn;               
        this.author = author;      
    }  
   
    public Object clone(){         
        
        Book b = null;           
        try {
             b = (Book)super.clone();
             /*
             //注释去掉后是深拷贝 可比较运行结果的差异
             author = (Person) author.clone();
             */
        }
        catch (CloneNotSupportedException e) {
             e.printStackTrace();
        }           
        return b;         
    }         
   
    public static void main(String args []) {   
        
        Person p = new Person("张三",55);
        Book b1 = new Book("Java编程",p);     
        Book b2 = (Book)b1.clone();   
        
        b2.getAuthor().setAge(66);   
        b2.getAuthor().setName("李四");     
        b2.bookName = "Java开发";   
        
        System.out.println(b1);
        System.out.println(b2);
    }
   
     
    public String toString(){            
        return (bookName + ", 变化在这里-引用变量的值--->>>" +  author ) ;            
    }
    public String getBookName() {
        return bookName;
    }
    public void setBookName(String bookName) {
        this.bookName = bookName;
    }
    public Person getAuthor() {
        return author;
    }
    public void setAuthor(Person author) {
        this.author = author;
    }   
}
希望有用。

评分

参与人数 1技术分 +1 收起 理由
韩军博 + 1 很给力!

查看全部评分

回复 使用道具 举报
来学习的,之前还不知道呢
回复 使用道具 举报
深拷贝与浅拷贝探析(在网上看到的)
1.          深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。比较典型的就是Value(值)对象,如预定义类型Int32,Double,以及结构(struct),枚举(Enum)等。考虑以下写法
        int source = int.MaxValue;//(1)初始化源对象为整数的最大值2,147,483,647
             int dest = source;//(2)赋值,内部执行深拷贝
             dest = 1024;//(3)对拷贝对象进行赋值
             source = 2048;//(4)对源对象进行赋值
        首先(2)中将source赋给dest,执行了深拷贝动作,其时dest和source的值是一样的,都是int.MaxValue;(3)对dest进行修改,dest值变为1024,由于是深拷贝,因此不会运行source,source仍然是int.MaxValue;(4)对source进行了修改,同样道理,dest仍然是1024,同时int.MaxValue的值也不变,仍然是2,147,483,647;只有source变成了2048。
        再考虑以下写法
         struct Point
         {
             public int X;
             public int Y;
             public Point(int x, int y)
             {
                 X = x;
                 Y = y;
             }
         }

         Point source = new Point(10, 20);
         Point dest = source;

         dest.X = 20
      当dest.X属性变成20后,source的X属性仍然是10

2.          浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。举个例子,一个人一开始叫张三,后来改名叫李四了,可是还是同一个人,不管是张三缺胳膊少腿还是李四缺胳膊少腿,都是这个人倒霉。比较典型的就有Reference(引用)对象,如Class(类)。
考虑以下写法
         class Point
         {
             public int X;
             public int Y;
             public Point(int x, int y)
             {
                 X = x;
                 Y = y;
             }
         }

         Point source = new Point(10, 20);
         Point dest = source;
    dest.X = 20;
由于Point现在是引用对象,因此Point dest=source的赋值动作实际上执行的是浅拷贝,最后的结果应该是source的X字段值也变成了20。即它们引用了同一个对象,仅仅是变量明source和dest不同而已。
3.          引用对象的浅拷贝原理
引用对象之间的赋值之所以执行的是浅拷贝动作,与引用对象的特性有关,一个引用对象一般来说由两个部分组成
(1)一个具名的Handle,也就是我们所说的声明(如变量)
(2)一个内部(不具名)的对象,也就是具名Handle的内部对象。它在Manged Heap(托管堆)中分配,一般由新增引用对象的New方法是进行创建
        如果这个内部对象已被创建,那么具名的Handle就指向这个内部对象在Manged Heap中的地址,否则就是null(从某个方面来讲,如果这个具名的handle可以被赋值为null,说明这是一个引用对象,当然不是绝对)。两个引用对象如果进行赋值,它们仅仅是复制这个内部对象的地址,内部对象仍然是同一个,因此,源对象或拷贝对象的修改都会影响对方。这也就是浅拷贝
4.          引用对象如何进行深拷贝
由于引用对象的赋值仅仅是复制具名Handle(变量)指向的地址,因此要对引用对象进行深拷贝就要重新创建一份该对象的实例,并对该对象的字段进行逐一赋值,如以下写法
         class Point
         {
             public int X;
             public int Y;
             public Point(int x, int y)
             {
                 X = x;
                 Y = y;
             }
         }

         Point source = new Point(10, 20);
         Point dest = new Point(source.X, source.Y);
         //或以下写法
         //Point dest = new Point()
         //dest.X = source.X
    //dest.Y = source.Y
        其时,source和dest就是两个互相独立的对象了,两者的修改都不会影响对方

5.一些需要注意的东西
        (1):String字符串对象是引用对象,但是很特殊,它表现的如值对象一样,即对它进行赋值,分割,合并,并不是对原有的字符串进行操作,而是返回一个新的字符串对象
        (2):Array数组对象是引用对象,在进行赋值的时候,实际上返回的是源对象的另一份引用而已;因此如果要对数组对象进行真正的复制(深拷贝),那么需要新建一份数组对象,然后将源数组的值逐一拷贝到目的对象中

评分

参与人数 1技术分 +1 收起 理由
韩军博 + 1 神马都是浮云

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马