`
enetor
  • 浏览: 188417 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java clone 详解

阅读更多

转载

 

我们知道,Java是纯面向对象的程序设计语言。Java里,所有的类的顶级父类都是java.lang.Object类,也就是说,如果一个类没有显示申明继承关系,它的父类默认就是java.lang.Object。
                                                                                   
   有一个很简单的方法可以证明这一点,我们写一个Test类,如下:

public class Test {
    public void someMethod() {
        super.clone();
    }
} 
 


里面调用了super.clone(),编译时并不报错。其实clone()方法为java.lang.Object类提供的一个protected型方法。



对象克隆
本文通过介绍java.lang.Object#clone()方法来说明Java语言的对象克隆特性。
java.lang.Object#clone()方法由java.lang.Object加以实现,主要对对象本身加以克隆。
首先我们看看下面的例子:

public class TestClone {
    public static void main(String[] args) {
        MyClone myClone1 = new MyClone("clone1");
       
        MyClone myClone2 = (MyClone)myClone1.clone();
       
        if (myClone2 != null) {
            System.out.println(myClone2.getName());
            System.out.println("myClone2 equals myClone1: " + myClone2.equals(myClone1));
        } else {
            System.out.println("Clone Not Supported");
        }
    }
} 
 

 

class MyClone {
    private String name;
    public MyClone(String name) {
        this.name = name;
    }
   
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
   
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    } 
 


编译执行TestClone,打印出:

C:\clone>javac *.java
C:\clone>java TestClone
Clone Not Supported
C:\clone>

说明MyClone#clone()方法调用super.clone()时抛出了CloneNotSupportedException异常,不支持克隆。

为什么父类java.lang.Object里提供了clone()方法,却不能调用呢?

原来,Java语言虽然提供了这个方法,但考虑到安全问题, 一方面将clone()访问级别设置为protected型,以限制外部类访问;
另一方面,强制需要提供clone功能的子类实现java.lang.Cloneable接口,在运行期,JVM会检查调用clone()方法的 类,如果该类未实现java.lang.Cloneable接口,则抛出CloneNotSupportedException异常。

java.lang.Cloneable接口是一个空的接口,没有申明任何属性与方法。该接口只是告诉JVM,该接口的实现类需要开放“克隆”功能。

我们再将MyClone类稍作改变,让其实现Cloneable接口:
class MyClone implements Cloneable {
    ...//其余不做改变
}

编译执行TestClone,打印出:

C:\clone>javac *.java
C:\clone>java TestClone
clone1
myClone2 equals myClone1: false
C:\clone>

根据结果,我们可以发现:
1,myClone1.clone()克隆了跟myClone1具有相同属性值的对象
2,但克隆出的对象myClone2跟myClone1不是同一个对象(具有不同的内存空间)

小结:
如果要让一个类A提供克隆功能,该类必须实现java.lang.Cloneable接口,并重载java.lang.Object#clone()方法。

public class A extends Cloneable {
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            //throw (new InternalError(e.getMessage()));
            return null;
        }
    }
} 
 




对象的深层次克隆
  上例说明了怎么样克隆一个具有简单属性(String,int,boolean等)的对象。


但如果一个对象的属性类型是List,Map,或者用户自定义的其他类时,克隆行为是通过怎样的方式进行的?
很多时候,我们希望即使修改了克隆后的对象的属性值,也不会影响到原对象,这种克隆我们称之为对象的深层次克隆。怎么样实现对象的深层次克隆呢?

验证对象的克隆方式
为了验证对象的克隆方式,我们对上面的例子加以改进,如下(为了节省篇幅,我们省略了setter与getter方法):

public class TestClone {
    public static void main(String[] args) {
        //为克隆对象设置值
         MyClone myClone1 = new MyClone("clone1");
         myClone1.setBoolValue(true);
         myClone1.setIntValue(100);
       
        //设置List值
         List <Element>listValue = new ArrayList<Element>();
         listValue.add(new Element("ListElement1"));
         listValue.add(new Element("ListElement2"));
         listValue.add(new Element("ListElement3"));
         myClone1.setListValue(listValue);
       
        //设置Element值
         Element element1 = new Element("element1");
         myClone1.setElement(element1);
       
       
        //克隆
         MyClone myClone2 = (MyClone)myClone1.clone();
       
        if (myClone2 != null) {
           
            //简单属性
             System.out.println("myClone2.name=" + myClone2.getName()
                     + " myClone2.boolValue=" + myClone2.isBoolValue()
                     + " myClone2.intValue=" + myClone2.getIntValue() );
           
            //复合属性(List<Element>与Element)
             List clonedList = myClone2.getListValue();
             Element element2 = myClone2.getElement();
           
             System.out.println("myClone2.listValue.size():" + clonedList.size());
             System.out.println("myClone2.element.equals(myClone1.element):" + element2.equals(element1));
             System.out.println("myClone2.element.name:" + element2.getName());
           
            //下面我们测试一下myClone2.element是否等于myClone1.element
            //以及myClone2.listValue是否等于myClone1.listValue
            //为此,我们修改myClone2.element与myClone2.listValue,如果myClone1的相应值也跟着被修改了,则它们引用的是同一个内存空间的变量,我们认为它们相等
           
             clonedList.add("ListElement4");
           
             System.out.println("myClone1.listValue.size():" + listValue.size());
           
             element2.setName("Element2");
             System.out.println("myClone1.element.name:" + element1.getName());
           
         } else {
             System.out.println("Clone Not Supported");
         }       
       
     }

} 
 



class MyClone implements Cloneable {
    private int intValue;
    private boolean boolValue;
    private String name;
    private List <Element>listValue;
    private Element element;

    public MyClone(String name) {
         this.name = name;
     }

     ...//setter与getter方法(略)
}

class Element implements Cloneable   {
    private String name;
   
    public Element (String name) {
         this.name = name;
     }

     ...//setter与getter方法(略)
} 
 



编译执行TestClone,打印出:

C:\clone>javac *.java
C:\clone>java TestClone
myClone2.name=clone1 myClone2.boolValue=true myClone2.intValue=100
myClone2.listValue.size():3
myClone2.element.equals(myClone1.element):true
myClone2.element.name:element1
myClone1.listValue.size():4
myClone1.element.name:Element2
myClone2 equals myClone1: false
C:\clone>
我们发现,对于对象里的List,Element等复合属性,super.clone()只是简单地赋值,没有采取克隆手段。也就是说,修改被克隆后的对象值,会影响到原对象。

怎么进行深层次的克隆呢?
答案是,我们只能手动在重载的clone()方法里,对属性也分别采用克隆操作。当然条件是,属性类也得支持克隆操作

class MyClone implements Cloneable {
     ...
    public Object clone() {
        try {
             MyClone myClone = (MyClone)super.clone();
            //分别对属性加以克隆操作
             myClone.element = this.element.clone();
           
             myClone.listValue = new ArrayList();
            for (Element ele:this.listValue) {
                 myClone.listValue.add(ele.clone());
             }
                       
            return myClone;
         } catch (CloneNotSupportedException e) {
            return null;
         }
     }
     ...
} 
 


//让Element类也支持克隆操作
class Element implements Cloneable   {
     ...
    public Element clone() {
        try {
            return (Element)super.clone();
         } catch (CloneNotSupportedException e) {
            return null;
         }
     }
} 
 



深层次的克隆操作往往存在效率问题,尤其是需要让List,Map等集合类也支持深层次的克隆操作时。

总结:
本文结合范例,比较深入地介绍了Java语言的克隆属性,以及克隆的实现方法等。同时分析了深层次克隆的概念,实现,以及存在的问题等。 但是有没有更好的方法呢?当然,是有的,串行化来实现。

分享到:
评论

相关推荐

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

    Java中的clone方法详解_动力节点Java学院,动力节点口口相传的Java黄埔军校

    java_clone用法

    ### Java中的`clone`方法详解:浅拷贝与深拷贝 #### 一、引言 在Java中,`clone`方法提供了一种快速复制对象的方式。它属于`Object`类的一部分,但需要显式地在子类中声明并实现`Cloneable`接口才能正常使用。本文...

    Clone详解.doc

    Java中的克隆(Clone)机制是一种创建对象副本的方法,它允许程序员复制一个对象的状态,而不会影响原始对象。克隆在编程中常用于创建对象的独立副本,使得新副本与原对象之间相互独立,对其中一个对象的修改不会...

    Java clone方法详解及简单实例

    Java中的`clone`方法是Java语言提供的一种复制对象的机制,它允许创建一个现有对象的副本,这个副本具有与原始对象相同的状态,但它们是独立的实体,对其中一个对象的修改不会影响另一个。`clone`方法是Java `Object...

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

    Java中的clone方法详解 在Java语言中,clone方法是一个非常重要的概念,它允许对象被复制,从而创造出一个新的对象。下面我们将详细介绍Java中的clone方法,并讨论它的实现机制和应用场景。 什么是clone方法 ...

    java 中clone()的使用方法

    Java 中 clone() 的使用方法 Java 中的 clone() 方法是对象的复制方法,其主要作用是创建一个与原对象相同的新对象。下面将详细介绍 Java 中 clone() 方法的使用方法。 什么是 clone() 方法? clone() 方法是 ...

    Java中的数组复制(clone与arraycopy)代码详解

    Java中的数组复制(clone与arraycopy)代码详解 Java中的数组复制是通过clone和arraycopy两个方法来实现的。clone方法是Object类的protected方法,用于创建对象的副本,而arraycopy是System类的静态方法,用于将一...

    对象克隆(clone)详解.docx

    【对象克隆(clone)详解】 对象克隆是Java编程中的一个重要概念,它允许我们创建一个已有对象的副本,而不影响原始对象。在Java中,克隆主要涉及到`Object`类中的`clone()`方法,以及两种不同的克隆类型:浅克隆和...

    Java 数组复制clone方法实现详解

    首先,`clone()`方法是Java中的一个内置功能,它允许我们创建一个对象的浅拷贝。对于基本类型的数组,`clone()`会创建一个新的数组,然后复制原数组的所有元素到新数组中。然而,对于引用类型的数组(如对象数组),...

    详解JAVA 原型模式

    【Java原型模式详解】 原型模式(Prototype Pattern)是一种创建型设计模式,它的主要目标是通过复制现有的对象来创建新对象,以减少重复的构造过程,提高性能。在Java中,原型模式通常涉及到对象的克隆操作,即...

    详解java中的深拷贝和浅拷贝(clone()方法的重写、使用序列化实现真正的深拷贝)

    在Java中,浅拷贝可以通过实现`Cloneable`接口并重写`clone()`方法来完成。以下是一个简单的浅拷贝示例: ```java public class Person implements Cloneable { private String name; private int age; private ...

    JAVA_高级特性(hashCode,clone,比较器,Class反射,序列化)

    ### Java 高级特性详解 #### 一、`hashCode` `hashCode` 方法是 `Object` 类中的一个方法,用于返回对象的哈希码值。在 Java 中,哈希码经常被用于实现散列表(如 `HashMap` 和 `HashSet`)。为了确保散列表的正确...

    Java软件开发实战 Java基础与案例开发详解 6-2 object类 共7页.pdf

    ### Java软件开发实战:Java基础与案例开发详解 #### 6-2 Object类 在Java编程语言中,`Object`类扮演着极其重要的角色。它位于`java.lang`包内,是所有Java类的直接或间接父类。这意味着每一个自定义的类(除非...

    Java设计模式-原型模式详解

    Java 设计模式 - 原型模式详解 原型模式是 Java 设计模式之一,它用于创建对象时,指定创建对象的类型,并通过拷贝这些原型创建新的对象。该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原...

    Java函数习惯用法详解

    Java 函数习惯用法详解 Java 函数习惯用法是 Java 编程中非常重要的一部分,它直接影响着程序的效率和可读性。下面将对 Java 函数习惯用法进行详细的解释和总结。 一、equals() 函数 equals() 函数是 Java 中最...

    详解Java中Object 类的使用.rar

    这个压缩包文件"详解Java中Object 类的使用.rar"包含了对Java中Object类的深入探讨,通过阅读其中的"详解Java中Object 类的使用.txt"文本,我们可以了解到关于Object类的一些关键知识点。 1. **对象的创建与类型...

Global site tag (gtag.js) - Google Analytics