Java中Cloneable接口的浅复制与深复制_java cloneable string-程序员宅基地

技术标签: java常用  Cloneable  浅复制  深复制  

Java中的深拷贝(深复制)和浅拷贝(浅复制)

深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在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);
    }

}

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

本文转自:http://www.cnblogs.com/shuaiwhu/archive/2010/12/14/2065088.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/shangming150/article/details/80323825

智能推荐

关于JavaBean获取中文乱码问题_javabean get中文字符串-程序员宅基地

文章浏览阅读3.8k次,点赞2次,收藏7次。最近重新学习了一下JavaWeb的一些基础知识,今天在学习JavaBean时遇到了一个中文的乱码问题。当JavaBean获取表单中的数据有中文时就会出现乱码的现象。原因大概是因为MyEclipse对Java文件的默认编码是iso8859-1,而我们在jsp中的编码设置一般为utf-8,所以在获取中文时必然会出现乱码的现象。其实解决的方法很简单,只需要我们在Getter方法中用getBytes(_javabean get中文字符串

GSL Non-Complete Primer-程序员宅基地

文章浏览阅读163次。Bo Schwarzstein http://jedimaster.cnblogs.com/ 6/21/2008 写在狗屎一样的中国高等教育之前 摘要GNU Scientific Library(以下简称GSL)是来自开源社区的重磅礼物,历史悠久功能强大,集成了最基础的同时也是最重要的科学计算算法如BLAS、Monte Carlo积分等。本文讲解了其基本使用方法..._c++ ordinary differential equation

Windows用批处理文件设置自动或者手动获取IP地址_windows11批处理换网关-程序员宅基地

文章浏览阅读2.1k次。在工作和生活中,有的时候需要设置固定的IP、网关、DNS才能上网,有的时候需要设置为自动获取IP。通过Windows界面操作确实可以实现,但是比较慢,需要我们一步一步的操作,通过以下的批处理文件可以更加快速的实现一键切换。1、设置固定IP,脚本里面的IP、网关、DNS修改为自己环境下的对应信息echo offecho 设置固定IP....netsh interface IP set addr..._windows11批处理换网关

Horizon View 6-创建共享虚拟桌面池⑸-程序员宅基地

文章浏览阅读57次。当底层都准备以后,那么我们可以创建虚拟桌面了,当然虚拟桌面也可以创建共享和专用了,我这以创建共享虚拟桌面池为例: Automated Pool:桌面池中的计算机通过vSphere平台自动生成。 Manual Pool:桌面池中的计算机是物理机或其它虚拟机。 Terminal Services Pool:池中的计算机是微软的终端服务器。 Full Virtual..._horizon view可以共享模板吗

基于TCP的聊天室_mfc tcp聊天室,实现群聊和私聊-程序员宅基地

文章浏览阅读1.6w次,点赞19次,收藏177次。 综合案例基于TCP的聊天室,支持多个用户同时登陆服务器进行聊天。(相当于群)socket编程,做一对多的通信,必然要用到多线程,保证多个客户端(并行)登陆服务器时同时进行聊天。cs:客户端服务器 项目主要功能:1、使用socket网络编程,实现聊天室的服务端和客户端、实现多人聊天2、客户发消息给服务端,服务端采用多线程处理每个客户端的消息并转发具体实现:客户端:..._mfc tcp聊天室,实现群聊和私聊

JAVA毕业设计可视化工器具信息管理系统计算机源码+lw文档+系统+调试部署+数据库-程序员宅基地

文章浏览阅读73次。JAVA毕业设计可视化工器具信息管理系统计算机源码+lw文档+系统+调试部署+数据库本源码技术栈:项目架构:B/S架构开发语言:Java语言开发软件:idea eclipse前端技术:Layui、HTML、CSS、JS、JQuery等技术后端技术:JAVA运行环境:Win10、JDK1.8数 据 库:MySQL5.7/8.0源码地址:https://pan.baidu.com/s/17J9I6b5SdqoP-1WUUFDZHg?pwd=or2r最新计算机专业原创开发毕业设计源码+数据库是近期作品

随便推点

在Matplotlib图中插入LaTex公式_matplotlib latex-程序员宅基地

文章浏览阅读1.5w次。Matplotlib可以无缝的处理LaTex字体,在图中加入数学公式from matplotlib.patches import Polygonimport matplotlib.pyplot as pltimport numpy as np# 定义一个求积分的函数def func(x): return 0.3* (x**2) + (0.1*x) + 1# 定义积分区间a, b =_matplotlib latex

分布式系统架构设计原理与实战:如何进行分布式系统的测试-程序员宅基地

文章浏览阅读929次,点赞14次,收藏22次。1.背景介绍1. 背景介绍分布式系统是现代计算机科学中的一个重要领域,它涉及到多个计算节点之间的协同和通信。随着互联网的不断发展,分布式系统的应用范围不断扩大,从传统的Web应用、大型数据库、云计算平台到物联网等各个领域都广泛应用。分布式系统的测试是确保系统性能、可靠性、安全性等方面性能的关键环节。在分布式系统中,由于节点之间的通信和协同,测试的复杂性也随之增加。因此,了解分布式系统的..._分布式系统测试

栈的顺序存储结构 -- C++使用类模板实现_模板实现使用存储栈元素-程序员宅基地

文章浏览阅读518次。栈栈是先进后出的线性表。即限定只能在表的一段进行插入和删除操作的线性表。栈结构在计算机中有广泛的应用。常见的软件的”撤销”和”恢复”功能就是用栈实现的。栈的顺序存储结构示例代码template<typename T>class SqStack{public: SqStack(int k = 1); ~SqStack(){ delete[]m..._模板实现使用存储栈元素

分布式经典论文翻译集汇总(链接)_distributed snapshots: determining global states o-程序员宅基地

文章浏览阅读1.9k次。1 分布式系统领域经典论文翻译集 链接地址:http://duanple.blog.163.com/blog/static/709717672011330101333271/具体内容:sql&nosql年代记SMAQ:海量数据的存储计算和查询一.google论文系列1. google系列论文译序_distributed snapshots: determining global states of distributed systems 翻译

音频重采样和音量调整ffmpeg滤镜(二十一)_avfiltercontext 调节音频-程序员宅基地

文章浏览阅读2.7k次,点赞4次,收藏14次。前言ffmpeg内置了很多滤镜库,都封装在AVFilter模块中,通过这个滤镜模块可以用来更加方便的处理音视频。比如视频分辨率压缩滤镜scale(用来对视频的分辨率进行缩放),视频翻转滤镜transpose(对视频进行上下左右的翻转);音频格式转换滤镜aformat(它实际上最终是调用avresample滤镜实现的),volume(用来调整音量大小)等等。 关于ffmpeg的滤镜AVFilter源码及编译 1、默认情况下libavfilter模块会编译如下文件: OBJS = allfilte_avfiltercontext 调节音频

设计灵感合集|拟人化创意合成小动物,治愈可爱风插画作品_拟人动物头像合成设计 一组霸气冷酷风格的合成动物人像作品-程序员宅基地

文章浏览阅读941次。如果把动物拟人化,让它们和人一样会变成什么样子呢?这样题材的插画很受设计友们喜欢的。在汇聚设计灵感的 集设网把创意拟人化小动物插图插画设计作品制作成合成创意合集,方便设计和有兴趣的小伙伴,交流学习。网址:www.ijishe.com..._拟人动物头像合成设计 一组霸气冷酷风格的合成动物人像作品

推荐文章

热门文章

相关标签