1.clone()即对象所占"内存块"的复制;
2.因为改变的是基本类型字段的副本;
3.引用即指向对象的"指针",指针再怎么复制都是指向同一个对象;
4.一定要实现Cloneable//抛砖引玉,闪先

解决方案 »

  1.   

    我曾经认为
    1. Java的对象存储在一个连续区域里面
    2. clone()的时候,将这个区域的内容不加区分拷贝到另外一个区域
    是不是这样子呢?
      

  2.   

    为什么x为object的实例时,x.clone()!=x  是true呢?按道理应该相等嘛
      

  3.   

    还有还有
    2.Note that all arrays are considered to implement the interface Cloneable.
    也就是说数组都被实现了Cloneable接口了?3."shallow copy"浅复制和"deep copy"深复制怎么理解和区别啊?
      

  4.   

    to
    为什么x为object的实例时,x.clone()!=x  是true呢?按道理应该相等嘛克隆是制作一个对象的拷贝,
    对象的==,!=的比较是比较对象的句柄,不是比较其值。因为克隆生成一个新的对象,所以他们的存储地址不一样,即句柄不同,所以
      x为object的实例时,x.clone()!=x  是true
      

  5.   

    楼上的,你看看这句话,是英文资料上的
      But the reference type just clone the same object's reference. Therefore when you make a change in the data member object, the original and the clone will be both changed. 
      翻译一下:但引用类型仅仅克隆了这同一个对象的引用。因此,当你修改这个对象中的一个数据成员时,原始的和克隆的数据成员都会被改变。
      这么看来你所说的“克隆生成一个新的对象,所以他们的存储地址不一样,即句柄不同”不是不成立了?
      

  6.   

    Patrick_DK(疾风摩郎):
    理解有误,这里的reference是成员变量,复制时新clone的对象和被clone的对象里的这个成员变量的是相同,即两个reference指到了一个对象(不是clone和被clone的对象)上。这和c++里的shallow copy constructor一样,对指针类型只是简单的按值复制,所以出问题。
      

  7.   

    楼上的,俺没有学过C++啊你说我理解错误,是指英文翻译错了吗?reference我理解应该是句柄啊,也就是存放对象内容的地址的指针啊.对对象的克隆不是克隆reference吗?
      

  8.   

    简单的理解起来就是
    "shallow copy"实际上只是简单的创建了当前对象的一个拷贝(即将当前对象作为一个二进制的数据块复制到一个新的内存块中),对于改对象中的reference variable只复制了它的值而不是所指向的对象,因此在使用"shallow copy"的新拷贝中修改reference variable所指的对象会影响到原来被clone的对象。
    而"deep copy"则可以避免这种情况的发生。它不但创建了当前对象的一个拷贝,而且还复制了当前对象中可能有的(注意:此时的reference variable值reference variable已经与原来的不一样了)。当然,这不算完,reference variable所指向的对象中可能也包含了reference variable,同样也要对其进行"deep copy"。
    打个比方来说:
    这有点象复制一个网页到自己的机子上,但是"shallow copy"只复制了当前页面,它上面链接得页面并没有保存下来,而"deep copy"则不然,它将所有被链接的页面都复制了下来(当然了,不仅仅只是复制一层而已),这就有点像是扒网站了,呵呵。
      

  9.   

    抱歉,文字输入有误,这句话“(注意:此时的reference variable值reference variable已经与原来的不一样了)。”前应加上一句“reference variable所指向的对象”
      

  10.   

    举个例子
    class XXX
    {
      int i=1;
      boolean b=true;
      float f=3.3f;
    }
    XXX x=new XXX();
    这样初始化了一个XXX类的对象x,x应该表示的是整个对象内容(一个连续的内存块包括x.i,x.b,x.f)的首地址吧,
    然后x.clone();那么这个x.clone()的值究竟表示什么呢?也是表示x对象所占的内存块的首地址吗?
    如果这么理解,x.clone()=x不是要成立了吗?
    又糊涂了.....你们看我的认识究竟是哪个地方有问题啊
      

  11.   

    //CloneTest.java
    public class CloneTest
    {
        public static class MyCloneable 
        implements Cloneable
        {
            public int i;
            public StringBuffer s;
            public void pr()
            {
                System.out.println( "i=" + i + ", s=" + s.toString() );
            }
            public Object clone()
            throws CloneNotSupportedException, OutOfMemoryError
            {
                return super.clone();
            }
        }
        
        public static void main( String args[] )
        throws Exception
        {
            StringBuffer str = new StringBuffer( "AAA" );
            MyCloneable origin, cloned;
            origin = new MyCloneable();
            origin.i = 10;
            origin.s = str;
            cloned = (MyCloneable)origin.clone();
            System.out.println( "Origin: " );
            origin.pr();
            System.out.println( "Cloned: " );
            cloned.pr();
            cloned.s.append( "BBB" );
            System.out.println( "Cloned modified: " );
            cloned.pr();
            System.out.println( "Origin also modified: " );
            origin.pr();
        }
    }
    //Results
    Origin:
    i=10, s=AAA
    Cloned:
    i=10, s=AAA
    Cloned modified:
    i=10, s=AAABBB
    Origin also modified:
    i=10, s=AAABBB
      

  12.   

    天啊,昏头了,alou(),不是说inner class不能是static的吗?那你的程序怎么编译也通过了?哎,一波未平,一波又起
      

  13.   

    各位高手,先把俺理解错误的地方指出来吧,这样才好理解你们说的
    举个例子
    class XXX
    {
      int i=1;
      boolean b=true;
      float f=3.3f;
    }
    XXX x=new XXX();
    这样初始化了一个XXX类的对象x,x应该表示的是整个对象内容(一个连续的内存块包括x.i,x.b,x.f)的首地址吧,
    然后x.clone();那么这个x.clone()的值究竟表示什么呢?也是表示x对象所占的内存块的首地址吗?
    如果这么理解,x.clone()=x不是要成立了吗?
    你们看我的认识究竟是哪个地方有问题啊
      

  14.   

    以下是我的理解:
    什么例子中的x.clone()得到一个新的对象句柄,也就是说它在内存里头新开了一块,然后把x中值复制到新内存块中,意思就是在内存中实现copy,所以
    x.clone()!=x
    由于你的例子中类成员变量都是基本类型,所以算是一个deep copy。
    如果你的类A中有未实现克隆的类成员变量,则A.clone是一个"shallow copy",若要把类A变成一个可以deep copy的时候,
    你必须让A中所有未实现克隆的类成员变量的类也实现克隆。
      

  15.   

    楼上的
    1.你楼上的那段我的话究竟错在哪里?2.举个例子:类中有未实现克隆的类成员变量,则类.clone是个浅copy
      

  16.   

    x.clone()不是表示x对象所占的内存块的首地址//: Cloning.java
    // The clone() operation works for only a few
    // items in the standard Java library.
    import java.util.*;class Int {
      private int i;
      public Int(int ii) { i = ii; }
      public void increment() { i++; }
      public String toString() { 
        return Integer.toString(i); 
      }
    }public class Cloning {
      public static void main(String[] args) {
        Vector v = new Vector();
        for(int i = 0; i < 10; i++ )
          v.addElement(new Int(i));
        System.out.println("v: " + v);
        Vector v2 = (Vector)v.clone();
        // Increment all v2's elements:
        for(Enumeration e = v2.elements();
            e.hasMoreElements(); )
          ((Int)e.nextElement()).increment();
        // See if it changed v's elements:
        System.out.println("v: " + v);
      }
    } ///:~clone()方法产生了一个Object,后者必须立即重新造型为正确类型。这个例子指出Vector的clone()方法不能自动尝试克隆Vector内包含的每个对象——由于别名问题,老的Vector和克隆的Vector都包含了相同的对象。我们通常把这种情况叫作“简单复制”或者“浅层复制”,因为它只复制了一个对象的“表面”部分。实际对象除包含这个“表面”以外,还包括句柄指向的所有对象,以及那些对象又指向的其他所有对象,由此类推。这便是“对象网”或“对象关系网”的由来。若能复制下所有这张网,便叫作“全面复制”或者“深层复制”。
      

  17.   

    6.14.3  内部类属性内部类属性    类名称只能用在定义过的范围中,除非用限定的名称。    内部类的名称必须与所嵌套的类不同。    内部类可以被定义在方法中。    任何变量,不论是本地变量还是正式参数,如果变量被标记为final,那么,就可以被内部类中的方法访问。
        内部类有如下属性:
        类名称只能用在定义过的范围中,除非用在限定的名称中。内部类的名称必须与所嵌套的类不同。
        ......
        被自动地声明为static的内部类成为顶层类。这些内部类失去了在本地范围和其它内部类中使用数据或变量的能力。
        内部类不能声明任何static成员;只有顶层类可以声明static成员。因此,一个需求static成员的内部类必须使用来自顶层类的成员。
             --- http://www.csdn.net/Expert/topic/419/419171.shtm本来我是没有加static,但是这样在new的时候出错
    CloneTest.java:24: non-static variable this cannot be referenced from a static c
    ontext
            origin = new MyCloneable();
                     ^
    1 error
    也就是说这样new出来的this是不能够在static的main里面使用的。
    参考其它类似错误(比如在static方法里面引用普通的变量)的意思,再对照上面的话,就知道原因了。
    在没有static的情况下,MyCloneable是一个内部类,它只能够在这个类的范围内使用,这和普通变量一样,而static方法本质上并不是属于这个类的范围之内的,因此它只能够new顶级类,只有真正的CloneTest的方法才可以在MyCloneable不使用static修饰的时候去new它。
      

  18.   

    [各位高手,先把俺理解错误的地方指出来吧,这样才好理解你们说的
    举个例子
    class XXX
    {
      int i=1;
      boolean b=true;
      float f=3.3f;
    }
    XXX x=new XXX();
    这样初始化了一个XXX类的对象x,x应该表示的是整个对象内容(一个连续的内存块包括x.i,x.b,x.f)的首地址吧,
    然后x.clone();那么这个x.clone()的值究竟表示什么呢?也是表示x对象所占的内存块的首地址吗?
    如果这么理解,x.clone()=x不是要成立了吗?
    你们看我的认识究竟是哪个地方有问题啊 ]
    clone是有一点复杂的,大概是这样的:
    XXX x=new XXX();
    这是如果你想要clone这个x的话,你必须自己实现这个XXX:class XXX implements Cloneable{
      int i=1;
      boolean b=true;
      float f=3.3f;  public Object clone(){
          XXX y=new XXX();
          y.i=i;
          y.b=b;
          y.f=f;
          return y;
      }  public boolean equals(Object o){
          if(!(o instanceof XXX)) return false;
          if((((XXX)o).i)==i && (((XXX)o).b)==b && (((XXX)o).f)==f) return true;
          return false;
      }
    }public class Test{
    public static void main(String[] args){
    XXX x0=new XXX(); XXX x1=(XXX)x0.clone();
    System.out.println(x0.hashCode()+"   "+x1.hashCode());
    System.out.println(x1==x0);
    System.out.println(x0.getClass()+"   "+x1.getClass());
    System.out.println(x0.equals(x1));
    }
    }
      

  19.   

    我的理解:
    1.对于对象中的基本数据类型的成员变量,可以进行值的复制,这样就有了两个拷贝.
    2.对于复合类的对象(即包含其他类作为成员变量),它的非基本类型的成员变量所在的内存地址仅仅保存的是这个对象成员的首地址,所以复制的也仅仅是对象成员的首地址,所以说the default implementation of clone() is a shallow clone().如[hahaha88(忧郁的眼神,稀嘘的胡子喳)]所说的要想将这个shallow clone()变成deep clone(),就要自己实现. 
    就象c++中的将两个相同类的对象进行赋值时,如果,类中包含了指针类型的成员变量,那么仅仅复制指针中的内容,即两个指针指向了相同的地址,这是仅仅个类比,不是十分准确.不知我理解的是否准确,请高手指点.
      

  20.   

    to hahaha88(忧郁的眼神,稀嘘的胡子喳):看了你的程序,我觉得是不是说实现cloneable接口就一定要覆盖equals方法啊?
      

  21.   

    to Patrick_DK(疾风摩郎):
    [看了你的程序,我觉得是不是说实现cloneable接口就一定要覆盖equals方法啊?]这个问题略为复杂一点:
    - 首先一个正确的clone实现必须满足下列条件:
     1 x.clone() != x will be true
     2 x.clone().getClass() == x.getClass()will be true
     3 super.clone()被调用了
     4 x.clone().equals(x) will be true(一般是这样,但不绝对,取决于你)
     5 根据具体要求,决定是否/如何override Object.hashCode方法。 - 因为java.lang.Object的clone()方法是protected的,所以如果你想要让你的类
      可以被clone,你首先必须override这个clone方法,并且你的实现必须满足
      x!=x.clone()这个条件,即:如下实现是错的:
       class MyClass{
           public void clone(){
               super.clone();
               return this;
           }
       }   所以,一个正确的对于Object.clone()的override不会返回指向x的同一地址,
       你必须开出一个新的内存区域,这一点是由x!=c.clone()这个要求(不是语法限制)
       来保证的,否则如果返回同意内存地址,clone就没有意义了。- 现在我们已经知道,必须override clone()方法,那么是否必须要override equals方法?
      不一定。
      java.lang.Object对于equals的缺省实现是:
        public boolean equals(Object obj) {
    return (this == obj);
        }
      我们已经保证 x.clone() != x 了,所以如果你不override equals方法,则equals方法
      返回false。所以如果希望x.clone().equals(x),那么你必须override equals(...) 
      方法,以保证 x.clone().equals(x)。 一般来说我们要保证这一点,但这取决于我们将要
      怎么样用这个被我们clone出来的对象,许多操作(比如涉及到java.util.HashTable的
      操作),将要用到equals。你要根据你的需要来决定如何处理equals。一般来说要保证
      x.clone().equals(x)。EJB里有关于对equals的要求,具体我忘了,嘻嘻。  - 同样根据具体要求,决定是否/如何override Object.hashCode方法。 hashCode
        和clone()在某些操作中是有关系的,理由同上(equals). - 在你override clone()方法时,最好/必须调用super.clone(),这是一个好习惯。
      

  22.   

    补充:根据JDK文档,x.clone().getClass() == x.getClass()will be true这个
    条件不是绝对的,但一般做好保证。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 x, the expression: 
     x.clone() != xwill be true, and that the expression: 
     x.clone().getClass() == x.getClass()will be true, but these are not absolute requirements. While it is typically the case that: 
     x.clone().equals(x)will be true, this is not an absolute requirement. Copying an object will typically entail creating a new instance of its class, but it also may require copying of internal data structures as well. No constructors are called. 
    The method clone for class Object performs a specific cloning operation. First, if the class of this object does not implement the interface Cloneable, then a CloneNotSupportedException is thrown. Note that all arrays are considered to implement the interface Cloneable. 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. The class Object does not itself implement the interface Cloneable, so calling the clone method on an object whose class is Object will result in throwing an exception at run time. The clone method is implemented by the class Object as a convenient, general utility for subclasses that implement the interface Cloneable, possibly also overriding the clone method, in which case the overriding definition can refer to this utility definition by the call:  super.clone()
      

  23.   

    似乎不会太难理解的ya。
    Patrick_DK
    <java核心技术>有关于clone()的图解,对你不知道是否有帮助。
      

  24.   

    建议看看《Think in java》这本书,里面对clone讲的很清楚,很生动。