`
FengShen_Xia
  • 浏览: 279331 次
  • 性别: Icon_minigender_1
  • 来自: 东方水城
社区版块
存档分类
最新评论

Java Clone详述

    博客分类:
  • Java
阅读更多

经常听到有人说java中没有指针。事实如此吗?no,java是有指针的,只不过换了个名字而已,也就是我们经常提到的引用。我们知道,在java中一 切都是对象,那么我们如何操控对象?如何在成千上万的对象中找到我们所需的那个对象呢?又是如何让对象按照我们的意思来完成任务的呢?

Object o = new Object(); 

 

   这是java中最常见的语句了,在这句话中做了三件事。首先声明一个Object类型的变量o,在内存中为对象划分一块地址new Object(),将声明的变量指向内存中的对象。如此一来,我们就可以通过o来操纵对象了。就好像孩子们玩的遥控飞机,在空中飞行的是飞机,而使它做出 优美动作的却是孩子们手中的摇控器。
  "克隆"是如今听到的较多的词汇,听说已经将某只羊克隆了好几份了。但愿这种技术不要在人身上实验。java中也有"克隆",与现实世界的克隆一样,将一个实际存在的对象拷贝几份。如下:

//倒霉的羊
public class Sheep implements Cloneable{
private String name;
public void setName(String arg) {
name = arg;
}
public String getName() {
return name;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//克隆
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep = new Sheep(); //先得到那只羊的实例
sheep.setName("我是真的"); //给它做个记号
System.out.println("sheep.getName() = " + sheep.getName());
Sheep sheepClone = (Sheep)sheep.clone(); //开始克隆
System.out.println("sheepClone.getName() = " + sheepClone.getName());
}
} 
 


运行程序结果为:
sheep.getName() = 我是真的
sheepClone.getName() = 我是真的
   两只羊是一模一样的(哪怕那只羊瘸腿)。让我们来看看代码。首先要注意的是Sheep类实现了Cloneable接口(该接口属于java.lang 包,默认已经导入了),该接口中并没有定义要实现的方法,是个空接口,起标志作用。也就是说,实现了这个接口的羊就不再是只普通的羊,它是一只可以被克隆 的羊。再往下看,有个clone方法,返回Object类型的对象,并抛出CloneNotSupportedException异常。该方法覆写了父类 (Object)的clone方法,并在最后调用了super.clone(),这也意味着无论clone类继承结构是什么样的,super.clone ()都会直接或间接调用Object类的clone()方法。看看jdk帮助文档会发现,Object类的clone()是一个native方法,我们知 道,native方法的效率一般来说都是远高于java中的非native方法。这也说明了new一个对象,然后将原对象中的数据导入到新创建的对象中去 的做法是多么愚蠢。必须说明的是Object中的clone方法是protected的,所以要使用clone就必须继承Object类(默认)。并且为 了可以使其它类调用该方法,必须将其作用域设置为public。
  以上只是一个简单clone的实现。明天说说"影子clone"和"深度clone"。
  夜,深了。何为影子clone?先看一下例子。

//倒霉的羊
public class Sheep implements Cloneable{
private String name;
public void setName(String arg) {
name = arg;
}
public String getName() {
return name;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//羊圈
public class Sheepfold implements Cloneable {
public Sheep sheep;
public String name;
public Sheepfold() {
sheep = new Sheep();
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//克隆
public class Main {
public static void main(String[] args) throws Exception {
Sheepfold fold = new Sheepfold();
fold.name = "小羊圈";
fold.sheep.setName("小羊");
Sheepfold fold2 = (Sheepfold)fold.clone();
System.out.println(" fold2.name = " + fold2.name);
System.out.println(" fold2.sheep.getName() = " + fold2.sheep.getName());
fold2.name = "大羊圈";
fold2.sheep.setName("大羊");
System.out.println("=====================================");
System.out.println(" fold2.name = " + fold2.name);
System.out.println("* fold2.sheep.getName() = " + fold2.sheep.getName());
System.out.println(" fold.name = " + fold.name);
System.out.println("* fold.sheep.getName() = " + fold.sheep.getName());
System.out.println("=====================================");
}
} 
 


在这个例子中有三个类,Sheep和Sheepflod都实现了Cloneable接口,并且覆写了Object类的clone方法,说明这两个类是具有克隆能力的。注意一点,在Sheepflod中持有一个Sheep的实例,并在Main类中对其进行克隆,结果如下:
fold2.name = 小羊圈
fold2.sheep.getName() = 小羊
=====================================
fold2.name = 大羊圈
* fold2.sheep.getName() = 大羊
fold.name = 小羊圈
* fold.sheep.getName() = 大羊
=====================================

请 注意一下结果中带有"*"号的两条结果语句。fold2.sheep和fold.sheep的name都变为了"大羊",很奇怪是吗?在此之前,我们只对 fold2.sheep的name赋过值。为什么fold.sheep的name也变为了"大羊"呢?原因很简单,因为它们是指向同一个对象的不同引用。 从中可以看出,调用Object类中clone()方法时,首先在内存中划分一块同原对象相同的空间,然后将原对象的内容原样拷贝至新对象。我们知道, java中有基本数据类型,对于基本数据类型,这样的操作是没有问题的,但对非基本类型变量,它们保存的仅仅是对象的引用,这也是为什么clone后非基 本类型变量和原对象中的变量指向同一个对象的原因。可能你已经注意到,程序中用到了String类型,即对象,为什么没有出现引用指向同一地址的情况?这 是因为String是一个不可更改的类(immutable class),每次给它赋值时,都会产生一个新的String对象。如 String str = "a"; str += "b";在这两句代码中,当执行str += "b"时,实际上是重新成生了一个值为"ab"的 String对象,即重新分配了一块内存空间。以上clone方法通常被称为"影子clone"。"影子clone"给我们留下了一个问题,即多个引用指 向同一个对象。如何解决该问题呢?答案为"深度clone"。把上面的例子改成深度clone很简单,只需将Sheepfold的clone()方法改为 如下即可:

public Object clone() throws CloneNotSupportedException {
Sheepfold fold = (Sheepfold)super.clone();
sheep = (Sheep)fold.sheep.clone();
return fold;
}  
 

 

评论

相关推荐

    Java设计模式(第2版)中文版 高清版本 带书签

    Java中的`Cloneable`接口和`clone()`方法支持这种模式。 6. **适配器模式**:将一个类的接口转换成客户希望的另一个接口。适配器使原本不兼容的类可以一起工作。 7. **装饰器模式**:动态地给一个对象添加一些额外...

    java基础之集合面试题共4页.pdf.zip

    14. **集合的复制**:通过clone()、Arrays.copyOf() 或 Collection.clone() 方法可以实现集合的浅复制。深复制涉及对象的复杂性,需要额外的处理。 15. **集合的排序**:Collections.sort() 方法可以对List进行排序...

    Java面试宝典Beta5.0.pdf

    本文将根据提供的文件内容,梳理和详述Java面试中常见的知识点。 ### 第一章 内容介绍 在面试宝典的第一章内容介绍中,虽然没有给出具体内容,但是可以推测这将是宝典的概览或目录部分,为面试者提供对后续章节...

    java程序编码规范

    克隆方法**:实现`Cloneable`接口的类,需重写`clone()`方法,确保对象的深拷贝。 **9. 类方法**:编写具体业务逻辑,注重方法的独立性和功能性,避免冗余代码。 #### 三、总结 Java编码规范不仅限于上述几点,...

    java面试题目

    19. **clone()方法**:通常会调用`super.clone()`以创建新对象并复制属性。 20. **List、Map、Set特点**:List按顺序存储,允许重复元素;Set不允许重复元素;Map存储键值对,键唯一。 21. **遍历List**:如上所述...

    Java中类赋值的解释实例详解

    如果需要创建对象的副本,Java提供了克隆(`clone()`)方法或深拷贝技术,但这超出了类赋值的范畴,不在此处详述。 总的来说,Java中的类赋值是通过对象引用的复制来实现的,而不是对象本身。这种设计使得共享和...

    Linux软件安装并实现部署项目

    本教程将详述如何在Linux环境中安装一系列必备软件,包括JDK、Tomcat、MySQL、Maven、Git和Redis,以实现项目的云端部署。 首先,让我们从安装Java Development Kit (JDK)开始。JDK是开发和运行Java应用程序的基础...

    windows本地部署DataX-web

    ### Windows本地部署DataX-Web知识点详述 #### 一、概述 DataX-Web是一款集成了DataX的可视化管理工具,它简化了数据同步任务的创建过程,并提供了丰富的功能来支持不同数据源之间的同步需求。该工具支持包括但不...

    YOLO开发教程及案例

    ### YOLO开发教程及案例知识点详述 #### 一、YOLO简介 YOLO(You Only Look Once)是目前非常流行的实时目标检测系统之一。它通过单一的神经网络模型来预测目标边界框及其类别概率,相较于传统的多阶段检测算法...

    PALab4:第一次提交

    10. **代码管理**:了解Git的基本操作,如clone、commit、push、pull,以及分支管理和合并。 以上是对“PALab4:第一次提交”所涉及知识点的详细解析,涵盖了从基础到进阶的Java编程知识,以及软件开发的版本控制...

    docs-master.rar

    常见的源码文件格式有".c"(C语言)、".java"(Java)、".py"(Python)等,它们各有其特定的语法和编程规范。 在开源社区,源码的管理通常依赖于版本控制系统,如Git。"docs-master"可能是一个Git仓库的主分支,...

    some useful doc

    其核心概念包括仓库(Repository)、分支(Branch)、提交(Commit)、合并(Merge)和克隆(Clone)等。`git Magic`这份文档可能深入探讨了Git的工作原理和高级用法,如子模块(Submodules)、钩子(Hooks)以及...

    dubbo源码解读与实战.doc

    ### Dubbo源码解读与实战知识点详述 #### 一、Dubbo源码环境搭建 **1.1 开始前的准备** - **环境需求**:确保安装了Git、Maven(建议版本3.3+)、Java JDK 1.8或更高版本。 - **软件工具**:IDEA (IntelliJ IDEA)...

    Linux系统下的项目部署

    本文将详述在Linux环境下进行项目部署的关键步骤和注意事项,旨在帮助开发者更好地理解和实践这一过程。 首先,我们需要理解“源码”和“工具”这两个标签在Linux项目部署中的含义。源码指的是开发人员编写的原始...

    开发环境的搭建与芯片使用方法-综合文档

    本文将详述这两个核心主题,旨在帮助初学者快速入门,同时也为有经验的开发者提供一个复习和深化理解的平台。 一、开发环境的搭建 1. **操作系统选择**:开发环境通常基于Windows、Linux或macOS等操作系统。不同的...

    chm,中文开放api文档

    如`append()`用于在元素内部添加内容,`remove()`用于删除元素,`clone()`用于复制元素。 3. **事件处理(Events)**:jQuery 使得绑定和解绑事件处理器变得简单,例如`click()`、`change()`等,以及统一的事件...

    standard_or_guide:一系列开发环境安装指南或git的有用帮助

    本篇文章将详述“standard_or_guide”中涵盖的开发环境安装步骤以及Git的一些实用技巧,特别是`git stash`的用法。 一、开发环境安装指南 开发环境的搭建通常包括编程语言的安装、集成开发环境(IDE)的选择与配置...

    作业1:这是我重新提交作业的链接

    如果" Homework1-master"包含代码,可能涵盖了编程语言(如Python、Java、C++等)、数据结构、算法或者其他特定的编程概念。 然而,由于缺乏具体信息,我无法深入讨论这些可能的知识点。为了提供超过1000字的详细...

Global site tag (gtag.js) - Google Analytics