java Object对象的clone方法

参考copy链接:http://blog.csdn.net/bigconvience/article/details/25025561

在看原型模式,发现要用到clone这个方法,以前和朋友聊过,没怎么看过,刚好要用,就看看了。

源码解释:

    /**
     * Creates and returns a copy of this object.  The precise meaning
     * of "copy" may depend on the class of the object. The general
     * intent is that, for any object {@code x}, the expression:
     * <blockquote>
     * <pre>
     * x.clone() != x</pre></blockquote>
     * will be true, and that the expression:
     * <blockquote>
     * <pre>
     * x.clone().getClass() == x.getClass()</pre></blockquote>
     * will be {@code true}, but these are not absolute requirements.
     * While it is typically the case that:
     * <blockquote>
     * <pre>
     * x.clone().equals(x)</pre></blockquote>
     * will be {@code true}, this is not an absolute requirement.
     * <p>
     * By convention, the returned object should be obtained by calling
     * {@code super.clone}.  If a class and all of its superclasses (except
     * {@code Object}) obey this convention, it will be the case that
     * {@code x.clone().getClass() == x.getClass()}.
     * <p>
     * By convention, the object returned by this method should be independent
     * of this object (which is being cloned).  To achieve this independence,
     * it may be necessary to modify one or more fields of the object returned
     * by {@code super.clone} before returning it.  Typically, this means
     * copying any mutable objects that comprise the internal "deep structure"
     * of the object being cloned and replacing the references to these
     * objects with references to the copies.  If a class contains only
     * primitive fields or references to immutable objects, then it is usually
     * the case that no fields in the object returned by {@code super.clone}
     * need to be modified.
     * <p>
     * The method {@code clone} for class {@code Object} performs a
     * specific cloning operation. First, if the class of this object does
     * not implement the interface {@code Cloneable}, then a
     * {@code CloneNotSupportedException} is thrown. Note that all arrays
     * are considered to implement the interface {@code Cloneable} and that
     * the return type of the {@code clone} method of an array type {@code T[]}
     * is {@code T[]} where T is any reference or primitive type.
     * Otherwise, this method creates a new instance of the class of this
     * object and initializes all its fields with exactly the contents of
     * the corresponding fields of this object, as if by assignment; the
     * contents of the fields are not themselves cloned. Thus, this method
     * performs a "shallow copy" of this object, not a "deep copy" operation.
     * <p>
     * The class {@code Object} does not itself implement the interface
     * {@code Cloneable}, so calling the {@code clone} method on an object
     * whose class is {@code Object} will result in throwing an
     * exception at run time.
     *
     * @return     a clone of this instance.
     * @throws  CloneNotSupportedException  if the object‘s class does not
     *               support the {@code Cloneable} interface. Subclasses
     *               that override the {@code clone} method can also
     *               throw this exception to indicate that an instance cannot
     *               be cloned.
     * @see java.lang.Cloneable
     */
    protected native Object clone() throws CloneNotSupportedException;

一大串英文我看不怎么懂,都是看别人的博客和翻译文档的。

中文jdk文档:

clone

protected Object clone()
                throws CloneNotSupportedException
创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。这样做的目的是,对于任何对象 x,表达式:
x.clone() != x
为 true,表达式:
x.clone().getClass() == x.getClass()
也为 true,但这些并非必须要满足的要求。一般情况下:
x.clone().equals(x)
为 true,但这并非必须要满足的要求。
按照惯例,返回的对象应该通过调用 super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约定,则 x.clone().getClass() == x.getClass()。

按照惯例,此方法返回的对象应该独立于该对象(正被复制的对象)。要获得此独立性,在 super.clone 返回对象之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被复制对象的内部“深层结构”的所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那么通常不需要修改 super.clone 返回的对象中的字段。

Object 类的 clone 方法执行特定的复制操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出 CloneNotSupportedException。注意,所有的数组都被视为实现接口 Cloneable。否则,此方法会创建此对象的类的一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有被自我复制。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。

Object 类本身不实现接口 Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常。

返回:
此实例的一个副本。
抛出:
CloneNotSupportedException - 如果对象的类不支持 Cloneable 接口,则重写 clone 方法的子类也会抛出此异常,以指示无法复制某个实例。
另请参见:
Cloneable

cloneable接口的文档:

public interface Cloneable
此类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。

如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常。

按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。请参阅 Object.clone(),以获得有关重写此方法的详细信息。

注意,此接口不 包含 clone 方法。因此,因为某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。

从以下版本开始:
JDK1.0
另请参见:
CloneNotSupportedException, Object.clone()

现在可以知道的是,clone方法就是返回一个原对象的拷贝,默认走的是浅拷贝。克隆的目的是复制对象,但是新的对象是独立于原来的对象的,一般我们克隆出来的对象都在一些属性做了更改,这个时候需要小心一点,如果更改的属性是引用数据类型,可能会影响到原来的对象,如果都是基本数据类型则不怕。使用clone方法的前提是继承Cloneable接口,数组默认实现了Cloneable接口,默认走的是浅拷贝。

那么问题来了,什么是浅拷贝?什么是深拷贝呢?

2.浅克隆(shadow clone)

克隆就是复制一个对象的复本.若只需要复制对象的字段值(对于基本数据类型,如:int,long,float等,则复制值;对于复合数据类型仅复制该字段值,如数组变量则复制地址,对于对象变量则复制对象的reference。

例子:

[java] view plain copy

  1. public class ShadowClone implements Cloneable{
  2. private int a;   // 基本类型
  3. private int[] b; // 非基本类型
  4. // 重写Object.clone()方法,并把protected改为public
  5. @Override
  6. public Object clone(){
  7. ShadowClone sc = null;
  8. try
  9. {
  10. sc = (ShadowClone) super.clone();
  11. } catch (CloneNotSupportedException e){
  12. e.printStackTrace();
  13. }
  14. return sc;
  15. }
  16. public int getA()
  17. {
  18. return a;
  19. }
  20. public void setA(int a)
  21. {
  22. this.a = a;
  23. }
  24. public int[] getB() {
  25. return b;
  26. }
  27. public void setB(int[] b) {
  28. this.b = b;
  29. }
  30. }

然后进行测试:

[java] view plain copy

  1. public class Test{
  2. public static void main(String[] args) throws CloneNotSupportedException{
  3. ShadowClone c1 = new ShadowClone();
  4. //对c1赋值
  5. c1.setA(100) ;
  6. c1.setB(new int[]{1000}) ;
  7. System.out.println("克隆前c1:  a="+c1.getA()+" b="+c1.getB()[0]);
  8. //克隆出对象c2,并对c2的属性A,B,C进行修改
  9. ShadowClone c2 = (ShadowClone) c1.clone();
  10. //对c2进行修改
  11. c2.setA(50) ;
  12. int []a = c2.getB() ;
  13. a[0]=5 ;
  14. c2.setB(a);
  15. System.out.println("克隆前c1:  a="+c1.getA()+" b="+c1.getB()[0]);
  16. System.out.println("克隆后c2:  a="+c2.getA()+ " b[0]="+c2.getB()[0]);
  17. }
  18. }

结果为:

克隆前c1:  a=100 b=1000
克隆前c1:  a=100 b=5
克隆后c2:  a=50 b[0]=5

c1和c2的对象模型:

可以看出,基本类型可以使用浅克隆,而对于引用类型,由于引用的是内容相同,所以改变c2实例对象中的属性就会影响到c1。所以引用类型需要使用深克隆。另外,在开发一个不可变类的时候,如果这个不可变类中成员有引用类型,则就需要通过深克隆来达到不可变的目的。

3.深克隆(deep clone)

深克隆与浅克隆的区别在于对复合数据类型的复制。若对象中的某个字段为复合类型,在克隆对象的时候,需要为该字段重新创建一个对象。

例子:

[java] view plain copy

  1. public class DeepClone implements Cloneable {
  2. private int a;   // 基本类型
  3. private int[] b; // 非基本类型
  4. // 重写Object.clone()方法,并把protected改为public
  5. @Override
  6. public Object clone(){
  7. DeepClone sc = null;
  8. try
  9. {
  10. sc = (DeepClone) super.clone();
  11. int[] t = sc.getB();
  12. int[] b1 = new int[t.length];
  13. for (int i = 0; i < b1.length; i++) {
  14. b1[i] = t[i];
  15. }
  16. sc.setB(b1);
  17. } catch (CloneNotSupportedException e){
  18. e.printStackTrace();
  19. }
  20. return sc;
  21. }
  22. public int getA()
  23. {
  24. return a;
  25. }
  26. public void setA(int a)
  27. {
  28. this.a = a;
  29. }
  30. public int[] getB() {
  31. return b;
  32. }
  33. public void setB(int[] b) {
  34. this.b = b;
  35. }
  36. }

[java] view plain copy

结果为:

克隆前c1:  a=100 b=1000

克隆前c1:  a=100 b=1000
克隆后c2:  a=50 b[0]=5

对象模型:

上面是copy的,自己敲一敲:

两个准备的类:class Person implements Cloneable{
    @Override
    protected Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }

    String name;
    int age;
    Job job;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Job getJob() {
        return job;
    }

    public void setJob(Job job) {
        this.job = job;
    }

    @Override
    public String toString(){
        return "name: " + name + ",age: " + age + ",job:  " + job;
    }
}
class Job{
    String jobName;
    String address;

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
public class CloneTest {    @Test    public void shaowClone() throws Exception{        Person p1 = new Person();        p1.setName("guo");        p1.setAge(22);        Job job = new Job();        job.setJobName("IT");        job.setAddress("shanghai");        p1.setJob(job);

Person p2 = p1.clone();        System.out.println(p1.toString());        System.out.println(p2.toString());

p2.getJob().setJobName("programmer");        System.out.println(p1.getJob().getJobName());    }

  得到结果:    name: guo,age: 22,job: [email protected]    name: guo,age: 22,job: [email protected]    programmer

浅拷贝,就是Object默认的clone方法,完全的copy了这个类,基本数据类型copy了值,引用数据类型copy的是对象的引用,所以如果要对对象进行修改,可以使用深拷贝。
}

所谓的深拷贝,就是自己重写了一下clone方法,将引用变量变成值传递而不是引用传递。修改的代码;
 @Override
    protected Person clone() throws CloneNotSupportedException {
        Person ectype = (Person) super.clone();
        Job tmp = new Job();
        tmp.setJobName(ectype.getJob().getJobName());
        tmp.setAddress(ectype.getJob().getAddress());
        ectype.setJob(tmp);
        return ectype;
    }测试代码:
@Testpublic void shaowClone() throws Exception{    Person p1 = new Person();    p1.setName("guo");    p1.setAge(22);    Job job = new Job();    job.setJobName("IT");    job.setAddress("shanghai");    p1.setJob(job);

Person p2 = p1.clone();    System.out.println(p1.toString());    System.out.println(p2.toString());

p2.getJob().setJobName("programmer");    System.out.println(p2.getJob().getJobName());    System.out.println(p1.getJob().getJobName());}

结果:


 
 

over

时间: 2024-10-19 01:18:26

java Object对象的clone方法的相关文章

Java Object 对象创建的方式 [ 转载 ]

Java Object 对象创建的方式 [ 转载 ] @author http://blog.csdn.net/mhmyqn/article/details/7943411 显式创建 有4种显式地创建对象的方式: 1.构造器:用new语句创建对象,这是最常用的创建对象的方式. 2.反射:运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法. 3.克隆:调用对象的clone()方法. 4.序列化:运用反

Java Object 对象序列化和反序列化

Java Object 对象序列化和反序列化 @author ixenos 对象序列化是什么 1.对象序列化就是把一个对象的状态转化成一个字节流. 我们可以把这样的字节流存储为一个文件,作为对这个对象的复制(深拷贝):在一些分布式应用中,我们还可以把对象的字节流发送到网络上的其他计算机. 反序列化是把流结构的对象恢复为其原有形式 2.Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长.但

Java高级特性:clone()方法

目录 源码 深拷贝和浅拷贝 对象串行化实现拷贝 常见面试题 源码 public class Objcet{ protected native Object clone() throws CloneNotSupportedException(); } 由源码可知. 第一:Objcet类的clone()方法是一个native方法.native方法的执行效率一般远高于Java中的非native方法(一般不是java语言所写).这也解释了为什么要用Object的clone()方法,而不是先new一个类,

Java Object 对象序列化后的文件格式

Java Object 对象序列化后的文件格式 @author ixenos 1.文件开头: AC ED 2.序列化格式版本示例: 00 05 3.字符串对象示例: 74 2字节表示的字符串长度 字符串: 74 00 05 ixenos 4.类序列化示例:当存储一个对象时,其类也被存储: 类名 序列化版本号ID指纹 序列化方法 数据域 72 2字节的类名长度 类名 8字节的指纹 1字节的标志 //由在java.io.ObjectStream.Constant中定义的三位掩码(三个字节常量)构成

js object 对象 属性和方法的使用

1 //object 对象 属性和方法的使用 2 var person = new Object(); 3 4 person.name="张海"; 5 person.age="60"; 6 7 person.say=function(){ 8 console.log(person.name+"他在说话!"+"\t他已经"+person.age+"岁"); 9 }; 10 person.eat=functio

Java Object 对象上的wait(),notify(),notifyAll()方法理解

第一阶段理解(2017-7-27): Java 将wait(),notify(),notifyAll()方法放在Object对象上,也就是说任何一个对象都可以调用这个方法,这与”任何一个对象都有一个内置锁,可以用于线程同步“是照应的.因此,当某个线程要释放cpu争夺权,让自己进入等待状态时,调用 某个锁(对象)上的wait()方法,也就是让当前线程等待其它线程调用该锁上的notify()或notify()方法.线程间通过同步锁来实现等待与唤醒协作.简单例子: 1 package com.lyyc

Java中Object对象有哪些方法

一,所有方法 1. getClass() 2. hashCode()3. equals()4. toString()5. clone()6. wait()...7. notify()8. notifyAll()9. finalize() 二,每个方法详解 protected Object clone()创建并返回此对象的一个副本.boolean equals(Object obj)指示其他某个对象是否与此对象“相等”.protected void finalize()当垃圾回收器确定不存在对该对

Java Object类及其equals方法

基本概念: Object类位于java.lang包中,java.lang包包含着Java最基础和核心的类,在编译时会自动导入: Object类是所有Java类的祖先.每个类都使用 Object 作为超类.所有对象(包括数组)都实现这个类的方法.可以使用类型为Object的变量指向任意类型的对象 equals()方法:比较两个对象是否同一       如果两个对象具有相同的类型以及相同的属性值,则称这两个对象相等.如果两个引用对象指的是同一个对像,则称这两个变量同一.Object类中定义的equa

Java Object对象中的wait,notify,notifyAll的理解

wait,notify,notifyAll 是定义在Object类的实例方法,用于控制线程状态,在线程协作时,大家都会用到notify()或者notifyAll()方法,其中wait与notify是java同步机制中重要的组成部分,需要结合与synchronized关键字才能使用,在调用一个Object的wait与notify/notifyAll的时候,必须保证调用代码对该Object是同步的,也就是说必须在作用等同于synchronized(object){......}的内部才能够去调用ob