`
wcg2008er
  • 浏览: 5008 次
  • 性别: Icon_minigender_1
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

Java克隆(Clone)的应用

阅读更多
简介:

Java克隆(Clone)是Java语言的特性之一,但在实际中应用比较少见。但有时候用克隆会更方便更有效率。

对于克隆(Clone),Java有一些限制:
1、被克隆的类必须自己实现Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。Cloneable 接口实际上是个标识接口,没有任何接口方法。
2、实现Cloneable接口的类应该使用公共方法重写 Object.clone(它是受保护的)。某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。
3、在Java.lang.Object类中克隆方法是这么定义的:
protected Object clone()
                throws CloneNotSupportedException
创建并返回此对象的一个副本。表明是一个受保护的方法,同一个包中可见。
按照惯例,返回的对象应该通过调用 super.clone 获得。


引题:

举个例子说吧,现在有一个对象比如叫foo,你需要在创建当前对象的一个副本作为存根你能怎么做?

假如你不用Clone,那么你可以先new一个对象foo1:Foo foo1=new Foo(),然后用foo给foo1对象set值,这样就得到foo的副本foo1;除此之外,别无选择。

这样说,也许有人会觉得说的过于绝对了,不过事实如此啊。

要产生一个副本,那副本要不要内存?----当然要了,那就对了!既然需要内存,(不克隆的情况下)你不new还有什么办法呢?请大家时刻铭记对象是Java运行时产生的,驻留在计算机内存中。

常见错误:
下面我澄清几个初学者容易犯迷糊的错误,同样的问题,产生foo对象的副本:
1、Foo foo1=new Foo();
   foo1=foo;
   然后就想当然的认为副本foo1生成了!

错误原因:foo1没错是申请了内存,但是执行foo1=foo后,foo1就不在指向刚申请的内存区域了,转而指向foo对象的内存区域,这时候,foo1、foo指向了同一内存区域。刚才new的操作制造一堆垃圾等着JVM回收。

2、Foo foo1=foo;
错误原因:还是两个变量都指向了同一块内存。

3、有些老鸟更厉害一些:在Foo中定义一个返回自身的方法:
    public Foo getInstance(){
        return this;
    }

    然后,Foo foo1=foo.getInstance();

错误原因:同上,主要还是没有重新开辟内存,this在对象里是什么?----就是对象自己的引用!那么getInstance()自然返回的就是对象自己,反正又是两个对象穿了一条裤子----***,哈哈。错得心服口服吧。为了节省篇幅,我在最后写个例子,留给那些对此有异议的人看。

引入克隆

看了这么多方法都不行,还很麻烦!干脆用克隆吧,简单明了。

废话不说了,看例子:
定义两个类CloneFooA、CloneFooB,然后写个测试类CloneDemo分别克隆这两个类的对象,然后打印测试结果到控制台。


/**
* Created by IntelliJ IDEA.
* User: leizhimin
* Date: 2007-9-20
* Time: 19:40:44
* 简单类克隆实现
* 要实现克隆,必须实现Cloneable接口,这是一个标识接口,没有接口方法
* 实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。
* 按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。
*/
public class CloneFooA implements Cloneable {
    private String strA;
    private int intA;

    public CloneFooA(String strA, int intA) {
        this.strA = strA;
        this.intA = intA;
    }

    public String getStrA() {
        return strA;
    }

    public void setStrA(String strA) {
        this.strA = strA;
    }

    public int getIntA() {
        return intA;
    }

    public void setIntA(int intA) {
        this.intA = intA;
    }

    /**
     * @return 创建并返回此对象的一个副本。
     * @throws CloneNotSupportedException
     */
    public Object clone() throws CloneNotSupportedException {
        //直接调用父类的clone()方法,返回克隆副本
        return super.clone();
    }
}


/**
* Created by IntelliJ IDEA.
* User: leizhimin
* Date: 2007-9-20
* Time: 19:59:55
* 深度克隆对象,当类存在聚合关系的时候,克隆就必须考虑聚合对象的克隆
*/
public class CloneFooB implements Cloneable {
    private CloneFooA fooA;
    private Double douB;

    public CloneFooB(Double douB) {
        this.douB = douB;
    }

    public CloneFooB(CloneFooA fooA, Double douB) {
        this.fooA = fooA;
        this.douB = douB;
    }

    public CloneFooA getFooA() {
        return fooA;
    }

    public void setFooA(CloneFooA fooA) {
        this.fooA = fooA;
    }

    public Double getDouB() {
        return douB;
    }

    public void setDouB(Double douB) {
        this.douB = douB;
    }

    /**
     * 克隆操作
     *
     * @return 自身对象的一个副本
     * @throws CloneNotSupportedException
     */
    public Object clone() throws CloneNotSupportedException {
        //先调用父类的克隆方法进行克隆操作
        CloneFooB cloneFooB = (CloneFooB) super.clone();
        //对于克隆后出的对象cloneFooB,如果其成员fooA为null,则不能调用clone(),否则出空指针异常
        if (this.fooA != null)
            cloneFooB.fooA = (CloneFooA) this.fooA.clone();

        return cloneFooB;
    }
}


/**
* Created by IntelliJ IDEA.
* User: leizhimin
* Date: 2007-9-20
* Time: 19:52:01
* 测试类:分别克隆CloneFooA和CloneFooB类,并打印克隆前后的结果.
*/
public class CloneDemo {
    public static void main(String args[]) throws CloneNotSupportedException {
        //CloneFooA克隆前
        CloneFooA fooA1 = new CloneFooA("FooA", 11);
        System.out.println("CloneFooA的对象克隆前对象fooA1值为: " + fooA1.getStrA() + "," + fooA1.getIntA());
        //CloneFooA克隆后
        CloneFooA fooA2 = (CloneFooA) fooA1.clone();
        System.out.println("CloneFooA的对象克隆后对象fooA2值为: " + fooA2.getStrA() + "," + fooA2.getIntA());
        //比较fooA1和fooA2内存地址
        if (fooA1 == fooA2) System.out.println("比较fooA1和fooA2内存地址:相等!");
        else System.out.println("比较fooA1和fooA2内存地址:不相等!");

        System.out.println("-------------------------");

        //CloneFooB克隆前
        CloneFooB fooB1 = new CloneFooB(fooA1, new Double("33"));
        System.out.println("CloneFooB的对象克隆前对象fooB1值为: " + fooB1.getFooA().getStrA() + "," + fooB1.getFooA().getIntA() + " | " + fooB1.getDouB());
        //CloneFooB克隆后
        CloneFooB fooB2 = (CloneFooB) fooB1.clone();
        System.out.println("CloneFooB的对象克隆前对象fooB2值为: " + fooB2.getFooA().getStrA() + "," + fooB2.getFooA().getIntA() + " | " + fooB2.getDouB());

        if (fooA1 == fooA2) System.out.println("比较fooB1和fooB2内存地址:相等!");
        else System.out.println("比较fooB1和fooB2内存地址:不相等!");
    }
}

运行结果:

CloneFooA的对象克隆前对象fooA1值为: FooA,11
CloneFooA的对象克隆后对象fooA2值为: FooA,11
比较fooA1和fooA2内存地址:不相等!
-------------------------
CloneFooB的对象克隆前对象fooB1值为: FooA,11 | 33.0
CloneFooB的对象克隆前对象fooB2值为: FooA,11 | 33.0
比较fooB1和fooB2内存地址:不相等!

Process finished with exit code 0


反面教材:

最后,我给出我上面提出到最后要给出的反面例子。

随便写一个,在CloneFooA 的基础上做了少许改动,内容如下:

public class CloneFooA implements Cloneable {
    private String strA;
    private int intA;

    public CloneFooA(String strA, int intA) {
        this.strA = strA;
        this.intA = intA;
    }

    public String getStrA() {
        return strA;
    }

    public void setStrA(String strA) {
        this.strA = strA;
    }

    public int getIntA() {
        return intA;
    }

    public void setIntA(int intA) {
        this.intA = intA;
    }

    /**
     * @return 创建并返回此对象的一个副本。
     * @throws CloneNotSupportedException
     */
    public Object clone() throws CloneNotSupportedException {
        //直接调用父类的clone()方法,返回克隆副本
        return super.clone();
    }

    /**
     * @return 返回运行时的对象
     */
    public CloneFooA getInstance(){
        return this;
    }

    public static void main(String args[]){
        CloneFooA fooA=new CloneFooA("aa",11);
        System.out.println(fooA.getStrA()+"  "+fooA.getIntA());

        CloneFooA fooA1=fooA.getInstance();
        System.out.println(fooA1.getStrA()+"  "+fooA1.getIntA());
        if(fooA==fooA1) System.out.println("fooA和fooA1内存地址相等!");

        System.out.println("-------------------------");

        //改变后fooA或者fooA1中任何一个,看看另外一个是否会改变
        fooA1.setStrA("bb");
        System.out.println(fooA.getStrA()+"  "+fooA.getIntA());
        System.out.println(fooA1.getStrA()+"  "+fooA1.getIntA());

        if(fooA==fooA1) System.out.println("fooA和fooA1内存地址相等,改变fooA1后,fooA的值也跟着变化了");
    }
}

运行结果:

aa  11
aa  11
fooA和fooA1内存地址相等!
-------------------------
bb  11
bb  11
fooA和fooA1内存地址相等,改变fooA1后,fooA的值也跟着变化了

Process finished with exit code 0

_______________________________________________________________摘自e800技术客 Java    
分享到:
评论

相关推荐

    java clone的小例子

    在Java编程语言中,`clone()`方法是一个非常重要的概念,特别是在对象复制和克隆方面。这个小例子将帮助初学者理解如何在Java中使用`clone()`来创建对象的副本。让我们深入探讨`clone()`方法以及它在实际编程中的...

    java的深度克隆的例子

    首先,Java提供了两种基本的克隆方式:浅克隆(shallow clone)和深克隆。浅克隆仅仅复制对象本身,而不复制对象所引用的对象。而深克隆则会递归地复制对象及所有引用的对象,确保新创建的对象和原始对象及其引用的...

    java code clone

    Java代码克隆,通常指的是在编程过程中,两个或多个代码段具有相似或完全相同的功能,这种现象被称为代码重复或代码克隆。在大型项目中,代码克隆可能会导致维护困难、增加bug出现的可能性以及降低代码的可读性和可...

    java 深克隆浅克隆

    实现深克隆通常需要自定义实现,因为Java的`clone()`方法不支持自动深度克隆。一种常见的实现方法是序列化和反序列化对象。首先,将对象序列化为字节数组,然后从字节数组反序列化为新的对象。这种方法可以保证所有...

    Java中clone方法共6页.pdf.zip

    本资料"Java中clone方法共6页.pdf.zip"可能包含了关于如何理解和使用`clone()`方法的详细解释,以及它在实际开发中的应用示例。 `clone()`方法的主要用途是创建一个现有对象的副本,这个副本与原始对象具有相同的...

    clone 深度克隆对象

    在Java中,实现深度克隆通常有两种方式:一是通过实现Cloneable接口并重写Object类的clone()方法;二是使用序列化和反序列化技术。前者需要特别注意的是,只有实现了Cloneable接口的类才能调用默认的clone()方法,...

    克隆和序列化(Java )

    在Java编程语言中,克隆和序列化是两个...总结来说,Java中的克隆和序列化是两个强大的工具,它们在数据持久化、对象复制以及网络通信等方面有着广泛的应用。理解和熟练掌握这两个概念,对于Java开发者来说至关重要。

    Java对象的复制克隆

    Java中的对象复制与克隆是程序开发中常见的需求,主要用于创建一个对象的副本,而不会影响原始对象的状态。这里主要讨论两种类型的对象拷贝:浅拷贝和深拷贝。 浅拷贝,也称为表面拷贝,是创建一个新的对象,然后将...

    java中的指针,引用及对象的clone

    本文将深入探讨Java中的引用以及对象的克隆机制,包括浅拷贝和深拷贝的区别及其应用场景。 #### 二、Java中的引用 在Java中,当使用`new`关键字创建一个对象时,实际上创建的是一个指向该对象的引用。例如,以下...

    java深度克隆

    本文将详细介绍Java中的深度克隆技术,包括其实现原理及应用场景。 #### 二、深度克隆的重要性 在实际开发中,深度克隆具有重要意义: 1. **确保数据独立性**:深度克隆可以创建出与原对象完全独立的新对象,即使...

    Java对象的深克隆与浅克隆详解.zip(wcb2003)

    Java提供了两种主要的克隆方式:浅克隆(Shallow Clone)和深克隆(Deep Clone)。下面我们将深入探讨这两种克隆方法。 ### 浅克隆 浅克隆是指创建一个新的对象,其成员变量的值与原对象相同,但引用类型成员变量...

    对象克隆(clone)详解.docx

    在Java中,克隆主要涉及到`Object`类中的`clone()`方法,以及两种不同的克隆类型:浅克隆和深克隆。 一、克隆的原理与应用 `clone()`方法的工作原理是在堆上创建一个新的对象,这个新对象的内存分配与源对象相同,...

    java 对象克隆

    在Java中,克隆分为两种类型:浅克隆(Shallow Clone)和深克隆(Deep Clone)。浅克隆创建的新对象只复制了原对象的引用,这意味着如果原对象中包含可变的引用类型,如数组或复杂的数据结构,那么新对象和原对象会...

    Java中的clone方法详解_动力节点Java学院整理

    下面我们将详细介绍Java中的clone方法,并讨论它的实现机制和应用场景。 什么是clone方法 clone方法顾名思义,就是复制,在Java语言中,clone方法被对象调用,所以会复制对象。所谓的复制对象,首先要分配一个和源...

    clone()方法示例(对象克隆)_对象克隆_nervouse78_源码

    在Java编程语言中,`clone()`方法是一个非常重要的概念,特别是在处理对象复制和数据持久化时。本示例将深入探讨`clone()`方法的工作原理、使用场景以及如何在实际编程中应用。首先,我们来理解一下`clone()`方法的...

    关于java clone的一些基本的概念

    1. `clone`方法抛出`CloneNotSupportedException`,这意味着如果你尝试克隆一个没有实现`Cloneable`接口的对象,将会抛出异常。 2. 默认的`clone`方法创建的对象具有与原对象相同的类,且所有的字段值都相同(原始...

    如何进行Java对象的克隆.pdf

    Java 提供了一个特殊的 clone() 方法,为所有的引用类型提供了一套标准的克隆机制。 Java 中的对象克隆可以分为两种类型:浅克隆(Shallow Cloning)和深克隆(Deep Cloning)。 浅克隆是指创建一个新的对象,并将...

Global site tag (gtag.js) - Google Analytics