`

JAVA中浅复制与深复制

    博客分类:
  • Java
阅读更多

在家上网赚钱更容易

1.浅复制与深复制概念
⑴浅复制(浅克隆)
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
 
⑵深复制(深克隆)
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
 
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接口。
 
请看如下代码:

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;
         System.out.println(
"name="+s1.name+","+"age="+s1.age);//修改学生2后,不影响学生1的值。
    }

}

 

 说明:
①为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。
②继承自java.lang.Object类的clone()方法是浅复制。以下代码可以证明之。

class Professor 
{
    String name;
    
int age;
    Professor(String name,
int age)
    
{
        
this.name=name;
        
this.age=age;
    }

}

class Student implements Cloneable
{
    String name;
//常量对象。
    int age;
    Professor p;
//学生1和学生2的引用值都是一样的。
    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;
    System.out.println(
"name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授成为lisi,age为30。
    }

}

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

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 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;
         System.out.println(
"name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授不改变。
    }


}

 
3.利用串行化来做深复制
    把对象写到流里的过程是串行化(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 Professor implements Serializable
{
    String name;
    
int age;
    Professor(String name,
int age)
    
{
        
this.name=name;
        
this.age=age;
    }

}

class Student implements Serializable
{
    String name;
//常量对象。
    int age;
    Professor p;
//学生1和学生2的引用值都是一样的。
    Student(String name,int age,Professor p)
    
{
        
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)
    
{
           Professor p
=new Professor("wangwu",50);
           Student s1
=new Student("zhangsan",18,p);
           Student s2
=(Student)s1.deepClone();
           s2.p.name
="lisi";
          s2.p.age
=30;
          System.out.println(
"name="+s1.p.name+","+"age="+s1.p.age); //学生1的教授不改变。
     }

}

4.参考资料
⑴阎宏,Java与模式,电子工业出版社,2006
⑵孙鑫Java讲座视频资料
【转自www.bitsCN.com

在家上网赚钱更容易

分享到:
评论

相关推荐

    基于matlab实现的相移光纤光栅(FBG.rar

    基于matlab实现的相移光纤光栅(FBG.rar

    nfcPro-2020071702 id、ic读卡器软件

    配套设备仪器用

    数据更新至2020年分地区电源项目 建设本年施工规模.xls

    数据来源:中国电力统计NJ-2021版

    基于matlab实现烟花寻优算法,自己编的.rar

    基于matlab实现烟花寻优算法,自己编的.rar

    数据更新至2020年分电压等级35千伏及以上 企业自备变压器情况.xls

    数据来源:中国电力统计NJ-2021版

    基于Java的俄罗斯方块游戏的设计与实现

    俄罗斯方块游戏最初是由俄罗斯人阿列克谢·帕基特诺夫在1984年开发的休闲小游戏,曾几何时它创造了无可匹敌的商业价值,影响了一代休闲小游戏的开发与产业链。随着信息时代科技时代的不断发展和变化,计算机已经普及到每一个人的生活中,在繁忙的工作生活中,这一类休闲小游戏给人们带来了些许的放松。 这篇论文详细的描述分析了经典传统的俄罗斯方块实现的基本思路和一些基本游戏规则,在此基础之上,更进一步地开发出俄罗斯方块的创新创意模式,在经典游戏基础上开发出随着分数增高而等级增高难度加大的模式,并且创意性的开发出可操控方块颜色变换的模块,并且增添了游戏声音和音乐模块。本论文对上述功能给出了具体实现流程、详细描述、和一些源代码。 本论文阐述了俄罗斯方块游戏的开发和发展历史、开发此游戏的意义以及开发环境并根据软件工程开发软件和java编写程序的相关知识,对程序的需求分析、概要设计、详细设计与实现、调试运行进行了一系列描述。 此次程序设计是在Microsoft Windows 7系统下,以Java为开发语言,在Eclipse开发平台上进行游戏的设计与实现。

    一个基于ArkTS开源的鸿蒙next版的物流APP源代码

    一个基于ArkTS开源的鸿蒙next版的物流APP源代码

    (更新至2022年)就业基本情况.xls

    数据来源:中国人口与就业统计NJ-2023版

    node-v12.2.0-linux-armv7l.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    limbox86pcemulator_241983-3.apk

    limbox86pcemulator_241983-3.apk

    各地区分行业国有单位其他就业人员和平均工资(2022年).xls

    数据来源:中国劳动统计NJ-2023版

    node-v10.18.0-linux-armv7l.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    (更新至2022年)平均预期寿命.xls

    数据来源:中国人口与就业统计NJ-2023版

    2023年华数杯不透明制品最优配色方案设计B题全文

    2023年华数杯全国大学生数学建模大赛的大数据B题论文全文,文中框架完整,内容较为详细,此论文获得华数杯三等奖,为了避免二次外传,本文设置了水印,请各位注意文章隐私,同时由于限制,在此并未上传相关代码,若需要代码或答疑等服务,请私聊作者。 日常生活中五彩;缤纷的不透明有色制品是由着色剂染色而成。因此,不透明制品的配色对其外观美观度和市场竞争力起着重要作用。然而,传统的人工配色存在一定的局限性,如主观性强、效率低下等。因此,研究如何通过计算机方法来实现不透明制品的配色具有重要意义。 以下是部分题目 光通过物体传播有吸收、反射和透射三种方式。对于不透明制品来说,大部分光线会被其表面吸收或反射。吸收和反射的光线在经过透明度等校正后按波长分解成不同的颜色成分,形成光谱图。该光谱图通常由 400--700nm 波段的各色光组成。为简化计算,最终配色后的颜色的反射率以 20nm 为间隔的光谱数据来表示。对于不透明材料而言,吸收系数 K/散射系数 S 的比值与反射率 R 之间存在一定关系,具体请参考文献【1】《计算机配色理论及算法的研究》中的 K-M光学模型。基于光学模型得到的颜色参数,可应用于色

    华为 OD 机考攻略-加强版

    附件是 华为 OD 机考攻略_加强版,文件绿色安全,请大家放心下载,仅供交流学习使用,无任何商业目的!

    分行业城镇非私营单位就业人员工资总额(2003-2011年).xls

    数据来源:中国劳动统计NJ-2023版

    数据更新至2020年分地区单机6000千瓦及以上 水力发电机组分类情况(不足5万千瓦).xls

    数据来源:中国电力统计NJ-2021版

    基于C++qt 停车场管理系统源码+sql文件.zip

    Qt实现停车场管理软件 入库、出库、导航 Qt mysql操作 Qt 解析tiled生成的xml文件,并绘制图片 Qt 绘图 Qsql, QSqlDatabase, QtXml, QVector ,QImage, QPrinter .... 环境 ubuntu + mysql Todo install qt 5.3 install mysql 5 import sql file run

    分行业城镇非私营单位就业人员平均名义工资指数(2013-2022年).xls

    数据来源:中国劳动统计NJ-2023版

    数据更新至2020年电力企业线损电量.xls

    数据来源:中国电力统计NJ-2021版

Global site tag (gtag.js) - Google Analytics