Java的深拷贝和浅拷贝

转载 2012年03月24日 21:05:49
 熟悉C++的朋友对这个话题应该很熟悉,浅拷贝就是指两个对象共同拥有同一个值,一个对象改变了该值,也会影响到另一个对象。深拷贝就是两个对象的值相等,但是互相独立。本来想把以前写的一篇文章扩充一下,没想到居然牵扯出很多复杂的问题。本文测试环境是windows xp sp3中文版、NetBeans6.7.1,JDK1.6-update16。这里抛砖引玉,希望大家能提宝贵意见。

    首先,Java中常用的拷贝操作有三个,operator = 、拷贝构造函数 和 clone()方法。由于Java不支持运算符重载,我们无法在自己的自定义类型中定义operator=。拷贝构造函数大家应该很熟悉,现在看一下如何支持clone方法:

  1. 实现 Cloneable接口,因为 Object clone方法将检查类是否实现了 Cloneable接口,如果没有将抛出异常 CloneNotSupportedException对象。 Cloneable接口没有任何方法,只是个标志,所以只需要简单的写上 implements Cloneable即可。

  2. 改写从 Object继承而来的 clone方法,使它的访问权限为 public,因为为了防止意外的支持 clone操作, Object clone方法是 protected权限。


    通过上面的分析,可以看出,如果我们要给自己的类添加拷贝功能,我们可以添加拷贝构造函数和实现Cloneable接口。
    现在,来看一下不同的类型在拷贝过程中的表现:

  Operator = 拷贝构造函数 clone方法
预定义非集合类型 深拷贝 如果支持拷贝构造函数的类型,则是深拷贝 不支持
自定义类型 浅拷贝 取决于实现 取决于实现
预定义集合类型 浅拷贝 会逐个调用每个元素的operator=方法
会逐个调用每个元素的operator=方法


    下面是测试代码,首先测试的是预定义非集合类型的operator =操作:
        int x=1;
        int y=x;
        y=2;
        if(x!=y){
            System.out.println("deep copy");
        }


        Integer a=1;
        Integer b=a;
        b=2;
        if(!a.equals(b)){
            System.out.println("deep copy");
        }


        String m="ok";
        String n=m;
        n="no";
        if(!m.equals(n)){
            System.out.println("deep copy");
        }

        程序运行后,输出三行deep copy,测试结果表明,这三种类型的operator =操作都是深拷贝。由于我没有测试完所有的预定义非集合类型,我这里推测它们的operator =都是深拷贝。

    下面测试预定义非集合类型的拷贝构造函数:
        Integer a=1;
        Integer b=new Integer(a);
        b=2;
        if(!a.equals(b)){
            System.out.println("deep copy");
        }


        String m="ok";
        String n=new String(m);
        n="no";
        if(!m.equals(n)){
            System.out.println("deep copy");
        }

        程序运行后,输出两行deep copy,测试结果表明,这两种类型的拷贝构造函数都是深拷贝。int没有拷贝构造函数。
    
        现在我们来测试自定义类型的operator=操作,假设我有一个类Person,代码如下:
public class Person implements Cloneable{
    private int age;
    private String name;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    void setName(String name) {
        this.name = name;
    }
}
    测试代码:
        Person p=new Person();
        p.setAge(32);
        p.setName("陈抒");

        Person p2=p;
        p.setAge(33);
        p.setName("老陈");

        if( (p.getAge()!=p2.getAge())&&(!p.getName().equals(p2.getName())) ){
            System.out.println("deep copy");
        }

        运行后,没有输出deep copy,说明这是浅拷贝。这里就是我们常说的两个引用之间的赋值,仅仅是让两个引用指向同一个对象。

    现在,我们来测试预定义集合类型的operator=操作:
        ArrayList list1=new ArrayList();
        list1.add("yangzhou");
        ArrayList list2=list1;
        list1.clear();

        if(list2.isEmpty()){
            System.out.println("shallow copy");
        }

    结果输出为shallow copy。

    现在我来测试拷贝构造函数:
        ArrayList list1=new ArrayList();
        list1.add("yangzhou");
        ArrayList list2=new ArrayList(list1);
        list1.clear();

        if(list2.isEmpty()){
            System.out.println("shallow copy");
        }else{
            System.out.println("deep copy");
        }

        输出结果是deep copy;
    clone方法的测试代码只是将第三行换成list1.clone(),加上类型转换,这里不再贴代码了。结果也证明是深拷贝
    预定义集合类的深拷贝 实际上就是调用每个元素的operator =。如果元素都是自定义类型的化,实际上还是浅拷贝。现在来看测试代码:
    ArrayList list1=new ArrayList();
        Person p1=new Person();
        p1.setAge(32);
        p1.setName("陈抒");
        list1.add(p1);

        ArrayList list2=(ArrayList) list1.clone();
        list2.get(0).setName("chenshu");

        if(list2.get(0).getName().equals(list1.get(0).getName())){
            System.out.println("shallow copy");
        }else{
            System.out.println("deep copy");

        }
    
    输出为shallow copy,Person是自定义类型,它的operator =运算符只是引用之间赋值,是浅拷贝。因此当修改了list2的第一个元素指向的Person对象的name属性,也就是修改了list1第一个元素所指向的Person对象的name属性。对于这种拷贝,我自己起了一个名字,叫做第一层深拷贝。
   
    现在我们有了表格中的结论,自己实现拷贝构造函数或者clone方法的时候就心里有数多了。
    假如我的自定义类型内部成员变量都是预定义非集合类型,那么在clone方法中只需要调用Object.clone即可完成深拷贝操作。在拷贝构造函数中需要使用operator=来一个个的深拷贝;
    假如我们的自定义类型内部成员变量有一些预定义类型,另一些是自定义类型,如果要深拷贝的话,最好调用自定义类型成员变量的拷贝构造函数或者clone方法。下面是例子代码:

public class Company {
    public Company(){

    }

    public Company(Company c){
        name=c.name;
        person=new Person(c.person);
    }
    private String name;
    private Person person;

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Object clone() throws CloneNotSupportedException{
        Company c=new Company();
        c.setName(name);
        c.setPerson((Person) person.clone());
        return c;
    }
}

public class Person implements Cloneable{
    public Person(){

    }

    public Person(Person p){
        age=p.age;
        name=p.name;
    }
    private int age;
    private String name;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    
    @Override
    public Object clone() throws CloneNotSupportedException{
        return super.clone();
    }
}
    Person类的两个成员变量都是预定义非集合类型,所以只需要在clone方法中简单的调用super.clone()即可实现深拷贝。Company类有一个Person成员变量,因此要调用Person的clone方法。

原文链接:http://blog.csdn.net/sheismylife/article/details/4570121

java的深拷贝与浅拷贝

转载:http://www.2cto.com/kf/201401/273852.html Java中对象的创建 clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以...
  • lcg910978041
  • lcg910978041
  • 2016年07月22日 10:46
  • 7050

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

前言 这两天,男票兴奋地通知我,我的博客终于有排名了,刚好是20000名,原来都是千里之外。我也比较兴奋,在这里谢谢每一个看到我文章的同学。O(∩_∩)O哈哈~,为什么有一种颁奖典礼的赶脚。真的啦,...
  • XIAXIA__
  • XIAXIA__
  • 2014年12月01日 21:56
  • 6798

深入理解Java中对象的浅拷贝与深拷贝

参考博客:http://blog.csdn.net/lcg910978041/article/details/51992614 理解好浅拷贝和和深拷贝对于理解Java的内存模型有很大的帮助。 在这...
  • wnl_csdn
  • wnl_csdn
  • 2017年02月07日 22:27
  • 339

c++深拷贝和浅拷贝

C++中类的拷贝有两种:深拷贝,浅拷贝当出现类的等号赋值时,会调用拷贝函数 在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。当数据成员中没有指针时,浅...
  • u010700335
  • u010700335
  • 2014年10月06日 19:27
  • 1776

深拷贝和浅拷贝的理解与应用

深拷贝和浅拷贝的理解与应用 对象拷贝(Object Copy)就是将一个对象的属性拷贝到另一个有着相同类类型的对象中去。在程序中拷贝对象是很常见的,主要是为了在新的上下文环境中复用对象的部分或全部...
  • u014628388
  • u014628388
  • 2017年08月22日 23:55
  • 362

Java中的深拷贝与浅拷贝(一)

概述 JAVA中对象的拷贝分两种:深拷贝和浅拷贝。 对象的拷贝在内存中的体现即是在堆中新开辟一片空间,然后将要拷贝的对象拷贝一份到新开辟的空间上来。要拷贝的对象可能有各种基本数据类型的成员变量,也可能...
  • u013165504
  • u013165504
  • 2016年08月23日 16:48
  • 909

Java 数组 浅拷贝与深拷贝

http://www.cppblog.com/baby-fly/archive/2010/11/16/133763.html 定义一个数组int[] a={3,1,4,2,5}; int...
  • xiefengzel
  • xiefengzel
  • 2013年11月12日 17:04
  • 668

Java基础-深拷贝和浅拷贝的区别

最近这段时间太忙了。以至于之前一篇博文没办法写下去。 趁着今天早上有1个半小时的空闲,写一篇 深拷贝与浅拷贝   为什么要拷贝? Java克隆是为了得到一个 完全一致的对象。 相同点:对象完...
  • wangxueming
  • wangxueming
  • 2016年07月26日 13:29
  • 264

关于Python中深拷贝与浅拷贝的理解(一)---概念

缘由 用Python也有很长时间了,一直在做科学计算和爬虫采集方面的东西。自己的毕业论文涉及到编写一个科学计算的软件,也是用Python编写。界面采用PyQt。 软件的主体前段时间已经写好,最近在试算...
  • u014433413
  • u014433413
  • 2015年11月10日 20:15
  • 3073

java对象的浅拷贝和深拷贝

我们知道,每个对象都有拷贝其对象的能力,是因为每个对象都是一个Object子类,而Object提供clone方法,一个类实现了Cloneable接口就表示该类具备了被拷贝的能力,如果再覆写里面的clo...
  • HarderXin
  • HarderXin
  • 2014年12月03日 12:02
  • 1595
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java的深拷贝和浅拷贝
举报原因:
原因补充:

(最多只允许输入30个字)