- 浏览: 124350 次
- 性别:
- 来自: 上海
文章分类
最新评论
编程过程中常常遇到如下情况: 假设有一个对象obj1,在某处需要和obj1一样的实例obj2,强调obj1和obj2是两个独立的实例,只是在开始的时候,它们具有一样的属性。这种情况下,一般的一种解决方法是:重新new一个对象obj2,然后将obj1的属性字段值依次赋予obj2。该种方法可行,但是也比较土。java提供了clone方法,使用clone方法,我们可以高效地解决上述的问题。
在理解clone方法前,有必要先了解下浅拷贝(shallow copy)和深拷贝(deep copy)。先看一个与浅拷贝相关的代码段:
- public class FamilyInfo {
- public String address;
- public int memberNum;
- public FamilyInfo(String address, int memberNum) {
- super();
- this.address = address;
- this.memberNum = memberNum;
- }
- }
public class FamilyInfo { public String address; public int memberNum; public FamilyInfo(String address, int memberNum) { super(); this.address = address; this.memberNum = memberNum; } }
- public class Employee {
- public String name;
- public FamilyInfo familyInfo;
- public Employee(String name, FamilyInfo familyInfo) {
- super();
- this.name = name;
- this.familyInfo = familyInfo;
- }
- }
public class Employee { public String name; public FamilyInfo familyInfo; public Employee(String name, FamilyInfo familyInfo) { super(); this.name = name; this.familyInfo = familyInfo; } }
- public class CloneTest {
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- FamilyInfo familyInfoA=new FamilyInfo("No.1100 Lianhang Rd.",2);
- Employee employeeA=new Employee("Lily",familyInfoA);
- System.out.println("employeeA's address "+employeeA.familyInfo.address);
- Employee employeeB=employeeA;
- System.out.println("employeeB's address "+employeeB.familyInfo.address);
- System.out.println("---------------------");
- employeeA.familyInfo.address="No.1588 Pulian Rd.";
- System.out.println("employeeA's address "+employeeA.familyInfo.address);
- System.out.println("employeeB's address "+employeeB.familyInfo.address);
- }
- }
public class CloneTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub FamilyInfo familyInfoA=new FamilyInfo("No.1100 Lianhang Rd.",2); Employee employeeA=new Employee("Lily",familyInfoA); System.out.println("employeeA's address "+employeeA.familyInfo.address); Employee employeeB=employeeA; System.out.println("employeeB's address "+employeeB.familyInfo.address); System.out.println("---------------------"); employeeA.familyInfo.address="No.1588 Pulian Rd."; System.out.println("employeeA's address "+employeeA.familyInfo.address); System.out.println("employeeB's address "+employeeB.familyInfo.address); } }
我们可以看到,随着employeeA对象 familyInfo值的改变,employeeB对象的值也受到影响。产生这种现象的原因是java中
Employee employeeB=employeeA;这条语句实际上是直接将对象employeeA的引用赋予employeeB,这样两个引用指向的是同一个对象。因此,当emploA对象改变的时候,employeeB的值也改变了。这就是浅拷贝。浅拷贝只拷贝对象引用本身,而不去拷贝引用的成员属性。从这个层次上来说,深clone并不是特别困难,简单地说,就是创建好对象,再设置一些成员属性。
接下来看看java的clone技术是怎么实现深浅拷贝的。
java中跟克隆有关的两个类分别是Cloneable接口和Object类中的clone方法,通过两者的协作来实现克隆。首先看一下java api doc中关于Cloneable接口和Object类中的clone方法的描述:
java.lang.Cloneable 接口,
此类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException异常。 按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。请参阅 Object.clone(),以获得有关重写此方法的详细信息。
Cloneable接口没有任何方法,仅是个标志接口(tagging interface),若要具有克隆能力,实现Cloneable接口的类必须重写从Object继承来的clone方法,并调用Object的clone方法,重写后的方法应为public 的。注意的是:java默认的clone()方法是浅拷贝,若要拷贝基本类型外加String类型以外的类型,即聚合或组合类间关系的时候,就需要进行深拷贝了。此时,常用的解决方法是纵深clone,即克隆到基本类型,外加String类型以外,不能再克隆为止。如下述例子:
- public class FamilyInfo implements Cloneable{
- public String address;
- public int memberNum;
- public FamilyInfo(String address, int memberNum) {
- super();
- this.address = address;
- this.memberNum = memberNum;
- }
- public FamilyInfo clone(){
- FamilyInfo familyInfo=null;
- try {
- familyInfo=(FamilyInfo) super.clone();
- } catch (CloneNotSupportedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return familyInfo;
- }
- }
public class FamilyInfo implements Cloneable{ public String address; public int memberNum; public FamilyInfo(String address, int memberNum) { super(); this.address = address; this.memberNum = memberNum; } public FamilyInfo clone(){ FamilyInfo familyInfo=null; try { familyInfo=(FamilyInfo) super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return familyInfo; } }
- public class Employee implements Cloneable{
- public String name;
- public FamilyInfo familyInfo;
- public Employee(String name, FamilyInfo familyInfo) {
- super();
- this.name = name;
- this.familyInfo = familyInfo;
- }
- public Employee clone(){
- Employee employee=null;
- try {
- employee=(Employee) super.clone();
- if(this.familyInfo!=null){
- employee.familyInfo=this.familyInfo.clone();
- }
- } catch (CloneNotSupportedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return employee;
- }
- }
public class Employee implements Cloneable{ public String name; public FamilyInfo familyInfo; public Employee(String name, FamilyInfo familyInfo) { super(); this.name = name; this.familyInfo = familyInfo; } public Employee clone(){ Employee employee=null; try { employee=(Employee) super.clone(); if(this.familyInfo!=null){ employee.familyInfo=this.familyInfo.clone(); } } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return employee; } }
- public class CloneTest {
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- FamilyInfo familyInfoA=new FamilyInfo("No.1100 Lianhang Rd.",2);
- Employee employeeA=new Employee("Lily",familyInfoA);
- System.out.println("employeeA's address "+employeeA.familyInfo.address);
- Employee employeeB=employeeA.clone();
- System.out.println("employeeB's address "+employeeB.familyInfo.address);
- System.out.println("---------------------");
- employeeA.familyInfo.address="No.1588 Pulian Rd.";
- System.out.println("employeeA's address "+employeeA.familyInfo.address);
- System.out.println("employeeB's address "+employeeB.familyInfo.address);
- }
- }
public class CloneTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub FamilyInfo familyInfoA=new FamilyInfo("No.1100 Lianhang Rd.",2); Employee employeeA=new Employee("Lily",familyInfoA); System.out.println("employeeA's address "+employeeA.familyInfo.address); Employee employeeB=employeeA.clone(); System.out.println("employeeB's address "+employeeB.familyInfo.address); System.out.println("---------------------"); employeeA.familyInfo.address="No.1588 Pulian Rd."; System.out.println("employeeA's address "+employeeA.familyInfo.address); System.out.println("employeeB's address "+employeeB.familyInfo.address); } }
输出结果为:
可以看到,深拷贝后,两个对象彼此独立,不受影响。
发表评论
-
(转)JDK工具(查看JVM参数、内存使用情况及分析等)
2018-12-25 15:50 345https://www.cnblogs.com/z ... -
[转]jstat查看jvm的GC情况
2018-12-25 15:38 553jstat 1. jstat -gc pid ... -
转一个 jmap 的基本使用方法
2017-04-05 11:52 535原文:http://hbluojiahui.bl ... -
(转)JVM内存堆布局图解分析
2017-04-05 11:56 403转载原文出处:http://www.codeceo.com/ ... -
(转)系统吞吐量(TPS)、用户并发量、性能测试概念和公式
2017-03-27 11:19 452PS:下面是性能测试的主要概念和计算公式,记录下: 一.系 ... -
(转)深入理解Major GC, Full GC, CMS
2016-11-02 11:27 499原文:http://blog.csdn.net/iter_ ... -
(转)OpenSSL 1.0.0生成p12、jks、crt等格式证书的命令个过程
2016-07-26 18:51 664OpenSSL 1.0.0生成p12、jks、crt等格式 ... -
(转)Java 内存区域和GC机制
2016-07-26 14:09 368录 Java垃圾回收概况 Java内存区域 Java ... -
Understanding CMS GC Logs
2016-07-26 11:06 532Understanding CMS GC Logs By ... -
(转)Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
2016-07-08 17:56 600源地址:http://blog.csdn.net/lu ... -
linux下查看最占性能的JAVA进程
2016-03-08 11:58 634记录一下自己常用的linux系统命令,方便以后查阅,发觉记忆 ... -
(转,精)Java 多线程 并发编程
2015-10-10 19:50 800源地址:http://blog.csdn.n ... -
java虚拟机内存监控工具jps,jinfo,Jstack,jstat,jmap,jhat使用
2015-09-21 13:14 1202源地址:http://my.oschina. ... -
(转)JMM模型
2014-11-11 16:53 488源地址:http://blog.csdn.net/gt ... -
(转)《深入浅出 Java Concurrency》目录
2014-11-10 15:55 402原文地址:http://www.blogjava.net/x ... -
(转)TCP/IP、Http、Socket的区别
2014-08-21 10:32 813源地址: http://jingyan.baidu.com/ ... -
(转)Swift里的CAP理论和NWR策略应用
2014-08-12 17:25 612源地址:http://blog.sina.com.cn/s/ ... -
(转)Java多线程编程的常见陷阱
2014-06-25 13:14 498源地址:http://developer.51cto.com ... -
(转)Java 正确的做字符串编码转换
2014-03-11 21:52 657原文:http://hi.baidu.com/sodarf ... -
深入理解java内存模型系列文章
2013-12-30 10:57 438深入理解java内存模型系列文章 源地址: htt ...
相关推荐
Java中的对象创建主要有两种方式,即使用`new`操作符创建新对象以及通过`clone`方法...在实际编程中,还可以考虑使用其他技术,如拷贝构造函数或工厂方法,来替代或补充`clone`操作,以实现更安全、更可控的对象复制。
在Java中实现深拷贝通常需要自定义`clone`方法或者使用序列化和反序列化技术。 对于`Cloneable`接口,当一个类需要支持`clone`操作时,应当实现这个接口。不过要注意的是,`Cloneable`接口本身没有任何方法,只是一...
Java中的`clone`方法是Java语言提供的一种复制对象的机制,它允许创建一个现有对象的副本,这个副本具有与原始对象相同的状态,但它们是独立的实体,对其中一个对象的修改不会影响另一个。`clone`方法是Java `Object...
Java Web前台技术是Web应用程序开发中的重要组成部分,主要关注用户界面的设计、交互和用户体验。这份“Java Web前台技术”资料集全面涵盖了与之相关的多个关键知识点,旨在帮助开发者提升技能和效率。 一、HTML...
### Java 高级特性详解 #### 一、`hashCode` ...正确地重写 `equals` 和 `hashCode` 方法、使用 `Comparator` 进行排序、利用反射机制和序列化技术,以及实现 `clone` 方法都是开发高质量 Java 应用程序的重要技能。
以下是一些关键的Java知识点,源自《Java技术要点与面试经典2013版》的部分内容: 1. 一个".java"源文件可以包含多个类,但只能有一个公开类(public class),其他类可以是非公开的(如private或默认包访问)。...
在Java中,浅拷贝可以通过实现`Cloneable`接口并重写`clone()`方法来完成。以下是一个简单的浅拷贝示例: ```java public class Person implements Cloneable { private String name; private int age; private ...
这是Java语言继承体系的基础,所有的类都继承自Object类,这意味着Object类中的方法在Java的任何对象中都可用,比如equals()、hashCode()、toString()、clone()等。clone()方法是一个特殊的对象复制方法,实现浅克隆...
7. Java的clone()方法在实现时,通常会有一行代码是调用super.clone()。 8. 面向对象编程的三大特性:封装、继承、多态,是Java语言的核心知识点。 9. Java中的多态实现机制是通过方法重载(Overloading)和方法...
在Java编程语言中,数组是一种基础且重要的数据结构,它用于存储同类型的多个元素。数组复制是编程中常见的操作,特别是在处理数据时需要备份或移动数据的场景。本篇文章将深入探讨Java中数组的复制方法及其相关知识...
Java面试的准备可以分为几个部分,其中最重要的部分是Java技术相关,包括了Java的基础知识、核心API的解读以及Java中高级技术的理解。同时,面试者应该熟悉应聘流程,了解如何撰写简历,以及在面试中如何谈论福利...
此外,书中还涉及了对象克隆(clone)的概念,这是Java中实现对象深度复制的技术。 Java SE语法是程序员必须掌握的基础,包括Java语言中的关键字和特殊符号的使用,例如“&”和“&&”的区别、goto语句的不存在、...
虚拟机克隆是虚拟化技术中的一个重要特性,它允许从一个运行的或停止的虚拟机创建一个完全一样的新虚拟机。 6. **数据备份和恢复** 在数据备份领域,克隆也扮演着关键角色。通过克隆,用户可以创建一个与原始数据...
Java中的`Cloneable`接口和`Object`类的`clone()`方法支持原型模式的实现。 6. **适配器模式**:将一个类的接口转换成客户希望的另一个接口。在Java中,可以使用类适配器或接口适配器,使不兼容的接口能够协同工作...
文档中提到了在`clone()`方法中的异常处理,这表明文档可能涉及Java中的异常处理机制,包括`try`、`catch`、`finally`和`throw`关键字的使用。 11. Java类的继承和接口 文档提到了`implements`关键字,这涉及到Java...
《JAVA面试宝典》是一本全面涵盖Java技术体系和求职面试知识的指南,旨在帮助Java开发者准备面试,提升技能。本书共分为十章,从基础知识到框架应用,再到项目实战和面试题解析,覆盖了Java开发者的必备技能。 第一...
Java中提供了`clone()`方法支持浅复制。 6. **组合模式**:允许你将对象组合成树形结构来表现“整体/部分”层次结构。在Java UI组件树中广泛应用。 7. **装饰器模式**:动态地给一个对象添加一些额外的职责。Java...
GRPC-Java 源码环境构建是一个相对复杂的过程,需要具备一定的技术基础和经验。本文将详细介绍 GRPC-Java 源码环境构建的步骤和过程,旨在帮助读者快速搭建 GRPC-Java 源码环境。 一、Clone GRPC-Java 源码 GRPC-...