深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java。虽然java自动管理对象的回收,但对于深拷贝(深复制)和浅拷贝(浅复制),我们还是要给予足够的重视,因为有时这两个概念往往会给我们带来不小的困惑。

浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。举例来说更加清楚:对象A1中包含对B1的引用,B1中包含对C1的引用。浅拷贝A1得到A2,A2 中依然包含对B1的引用,B1中依然包含对C1的引用。深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2 中包含对C2(C1的copy)的引用。

若不对clone()方法进行改写,则调用此方法得到的对象即为浅拷贝,下面我们着重谈一下深拷贝。

运行下面的程序,看一看浅拷贝:

class Professor0 implements Cloneable {
    String name;
    int age;
 
    Professor0(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
 
class Student0 implements Cloneable {
    String name;// 常量对象。
    int age;
    Professor0 p;// 学生1和学生2的引用值都是一样的。
 
    Student0(String name, int age, Professor0 p) {
        this.name = name;
        this.age = age;
        this.p = p;
    }
 
    public Object clone() {
        Student0 o = null;
        try {
            o = (Student0) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println(e.toString());
        }
 
        return o;
    }
}
 
public class ShallowCopy {
    public static void main(String[] args) {
        Professor0 p = new Professor0("wangwu", 50);
        Student0 s1 = new Student0("zhangsan", 18, p);
        Student0 s2 = (Student0) s1.clone();
        s2.p.name = "lisi";
        s2.p.age = 30;
        s2.name = "z";
        s2.age = 45;
        System.out.println("学生s1的姓名:" + s1.name + "\n学生s1教授的姓名:" + s1.p.name + "," + "\n学生s1教授的年纪" + s1.p.age);// 学生1的教授
    }
}

s2变了,但s1也变了,证明s1的p和s2的p指向的是同一个对象。这在我们有的实际需求中,却不是这样,因而我们需要深拷贝:

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;
    }
}
 
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 class DeepCopy {
    public static void main(String args[]) {
        long t1 = System.currentTimeMillis();
        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);// 学生1的教授不改变。
        long t2 = System.currentTimeMillis();
        System.out.println(t2-t1);
    }
}

当然我们还有一种深拷贝方法,就是将对象串行化:

import java.io.*;
//Serialization is time-consuming
class Professor2 implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    String name;
    int age;
 
    Professor2(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
 
class Student2 implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    String name;// 常量对象。
    int age;
    Professor2 p;// 学生1和学生2的引用值都是一样的。
 
    Student2(String name, int age, Professor2 p) {
        this.name = name;
        this.age = age;
        this.p = p;
    }
 
    public Object deepClone() throws IOException, OptionalDataException,
            ClassNotFoundException {
        // 将对象写到流里
        ByteArrayOutputStream 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 class DeepCopy2 {
 
    /**
     * @param args
     */
    public static void main(String[] args) throws OptionalDataException,
            IOException, ClassNotFoundException {
        long t1 = System.currentTimeMillis();
        Professor2 p = new Professor2("wangwu", 50);
        Student2 s1 = new Student2("zhangsan", 18, p);
        Student2 s2 = (Student2) s1.deepClone();
        s2.p.name = "lisi";
        s2.p.age = 30;
        System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age); // 学生1的教授不改变。
        long t2 = System.currentTimeMillis();
        System.out.println(t2-t1);
    }
 
}

但是串行化却很耗时,在一些框架中,我们便可以感受到,它们往往将对象进行串行化后进行传递,耗时较多。

Java中的深拷贝(深复制)和浅拷贝(浅复制)的更多相关文章

  1. Java中的深拷贝和浅拷贝(转载)

    深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽然java自动管理对象的回收,但对于深拷贝(深复 ...

  2. Java中的深拷贝和浅拷贝

    1.浅拷贝与深拷贝概念 (1)浅拷贝(浅克隆) 浅拷贝又叫浅复制,将对象中的所有字段复制到新的对象(副本)中.其中,值类型字段(java中8中原始类型)的值被复制到副本中后,在副本中的修改不会影响到源 ...

  3. 浅谈Java中的深拷贝和浅拷贝(转载)

    浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...

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

    转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...

  5. 内功心法 -- Java中的深拷贝和浅拷贝

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------这篇博客主要来谈谈" ...

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

    1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵ ...

  7. Java中的clone()----深复制,浅复制

    这篇文章主要介绍了Java中对象的深复制(深克隆)和浅复制(浅克隆) ,需要的朋友可以参考下 1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他 ...

  8. java基础(十七)----- 浅谈Java中的深拷贝和浅拷贝 —— 面试必问

    假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...

  9. 浅析Java中的深拷贝和浅拷

      浅析Java中的深拷贝和浅拷贝 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: in ...

随机推荐

  1. 001-ant design pro安装、目录结构、项目加载启动【原始、以及idea开发】

    一.概述 1.1.脚手架概念 编程领域中的“脚手架(Scaffolding)”指的是能够快速搭建项目“骨架”的一类工具.例如大多数的React项目都有src,public,webpack配置文件等等, ...

  2. Dora.Interception, 为.NET Core度身打造的AOP框架:不一样的Interceptor定义方式

    相较于社区其他主流的AOP框架,Dora.Interception在Interceptor提供了完全不同的编程方式.我们并没有为Interceptor定义一个接口,正是因为不需要实现一个预定义的接口, ...

  3. MySQL之存储引擎(Day39)

    一 什么是存储引擎 mysql中建立的库=====>文件夹 库中建立的表=====>文件 现实生活中我们用来存储数据的文件应该有不同的类型:比如存文本用txt类型,存表格用excel,存图 ...

  4. yum速查

    yum命令是在Fedora和RedHat以及SUSE中基于rpm的软件包管理器,它可以使系统管理人员交互和自动化地更细与管理RPM软件包, 能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖 ...

  5. redis 笔记04 服务器、复制

    服务器 1. 一个命令请求从发送到完成主要包括以下步骤: 1). 客户端将命令请求发送给服务器 2). 服务器读取命令请求,并分析出命令参数 3). 命令执行器根据参数查找命令的实现函数,然后执行实现 ...

  6. js防抖

    那我们设置个 options 作为第三个参数,然后根据传的值判断到底哪种效果,我们约定: leading:false 表示禁用第一次执行trailing: false 表示禁用停止触发的回调 我们来改 ...

  7. FTP 服务器性能 测试点

    测试FTP 服务器性能测试点: 1. ftp软件性能 2. ftp服务器硬件处理性能(IO/CPU/ROM) 3. ftp服务器网络吞吐性能 (NET IO) 有针对性的测试 达到的效果会比较好. 建 ...

  8. Json日期格式 转化为 YYYY-MM-DD-hh-mm-ss

    function timeStamp2String(time) { var datetime = new Date(); datetime.setTime(time); var year = date ...

  9. Centos 6\7 防火墙入门配置

    Centos 6 -- iptables iptables 用法: iptables (选项) (参数) 选项: -t<表>:指定要操纵的表: -A:向规则链中添加条目: -D:从规则链中 ...

  10. ubuntu 致命错误: zlib.h:没有那个文件或目录【转】

    本文转载自:https://blog.csdn.net/u013359794/article/details/44922685?locationnum=15&fps=1 编译时,出现错误,提示 ...