通过实现CLONEABLE接口和覆盖CLONE()方法实现深度克隆,以及如何通过BYTEARRAYIOSTREAM实现克隆

某个类要想实现拷贝的功能,就必须实现Cloneable接口,并覆盖Object的clone()方法,才能真正实现克隆。

浅拷贝,一种默认的实现,Teacher类中的clone方法的实现就是浅拷贝。

Student类的clone方法就是深拷贝。注意super.clone返回的对象实际上是被类的对象,可以放心强制转换,至于为什么,我也不知道,估计得读虚拟机规范,从Object源码看也不到什么,因为是protect native Object clone();


import java.util.*;
public class TestClone{
 
public static void main(String[] args)
 
{
  Teacher t 
= new Teacher("Name",22);
  Teacher m 
= (Teacher)t.clone();
  System.out.println(m);
  
  Student stu 
= new Student();
  Student deepcloneSTU 
= (Student)stu.clone();
  stu.courses.put(
new Integer(1),"Math");
  deepcloneSTU.courses.put(
new Integer(100),"Java");
  disp(stu.courses);
  disp(deepcloneSTU.courses);
  
 }

 
 
static void disp(HashMap h)
 
{
  Set keySet 
= h.keySet();
  Iterator it 
= keySet.iterator();
  
while(it.hasNext())
  
{
   System.out.println(h.get(it.next()));
  }

 }

}


class Teacher implements Cloneable{
 String name;
 
int age;
 Teacher(String name,
int age)
 
{
  
this.name = name;
  
this.age = age;
 }

 
 
public Object clone()
 
{
  
try{
   
return super.clone();
  }
catch(CloneNotSupportedException e)
  
{
   
throw new Error("This should never happen!"); 
  }

 }

 
 
public String toString()
 
{
  
return name + "  " + age;
 }

}


class Student implements Cloneable{
 HashMap courses 
= new HashMap();
 Student()
{} 
 
 
public Object clone()
 
{
  
try{
   Student stu 
= (Student)super.clone();
   stu.courses 
= (HashMap)courses.clone();
   
return stu;
  }
catch(CloneNotSupportedException e)
  
{
   
throw new Error("This should never happen!"); 
  }

 }

}




如何通过对象串行化的方式来做进行拷贝工作呢?

import java.util.*;
import java.io.*;
public class TestClone{
    
public static void main(String[] args) throws Exception
    
{
        BMW mycar 
= new BMW();
        ByteArrayOutputStream memoryOutputStream 
= new ByteArrayOutputStream();
        ObjectOutputStream serializer 
= new ObjectOutputStream(memoryOutputStream);
        serializer.writeObject(mycar);
        serializer.flush();
        
        ByteArrayInputStream memoryInputStream 
= new ByteArrayInputStream(memoryOutputStream.toByteArray( ));
        ObjectInputStream deserializer 
= new ObjectInputStream(memoryInputStream);
        BMW mycopycar 
= (BMW)deserializer.readObject();

        mycar.add(
new String("NB"));
        mycopycar.add(
new String("NBNB"));
      System.out.println(mycar.hashCode());
      System.out.println(mycopycar.hashCode());
      System.out.println(mycar.equals(mycopycar));
    }

}


class BMW implements Serializable
{
    
private int wheels;
  
private String model;
  
private ArrayList forTest;
  
  BMW()
  
{
      wheels 
= 4;
      model 
= "530i";
      forTest 
= new ArrayList();
  }

  
  
public void add(Object o)
  
{
      forTest.add(o);
  }

  
  
public String toString()
  
{
      
return "WHEEL:" + wheels + "MODEL:" + model + forTest.toString();    
  }

  
  
public int hashCode()
  
{
      
return wheels + model.hashCode() + forTest.hashCode();    
  }

  
  
public boolean equals(Object o)
  
{
      
if(o == this)
          
return true;
      
if(o == null)
          
return false;
      
if(!(o instanceof BMW))
        
return false;
      BMW bmw 
= (BMW)o;
      
if(bmw.wheels == wheels&&bmw.model.equals(model)&&bmw.forTest.equals(forTest))
          
return true;
      
else return false;
  }
  
}


记住,如果覆盖了equals方法,应该也覆盖hashCode(),因为如果两个对象相等也就是equals()返回true,那么这两个对象应该有相同的hashCode。

 

http://www.blogjava.net/lhulcn618/archive/2006/01/08/27157.html

 

 

今天看了一上午关于clone()和cloneable interface 的文章,我推荐一篇供大家参考学习。

蓝色为我的翻译,有不当之处,大家多多包涵!

 

clone() and the Cloneable Interface in Java

 

 

......The clone( ) method generates a duplicate copy of the object on which it is called. Only classes that implement theCloneable interface can be cloned.

 

...clone()产生了一个调用它的对象的复制;只有实现了Cloneable接口的类才可以被复制。

 

 

The Cloneable interface defines no members. It is used to indicate that a class allows a bitwise copy of an object (that is, a clone ) to be made. If you try to call clone( ) on a class that does not implement Cloneable , aCloneNotSupportedException is thrown. When a clone is made, the constructor for the object being cloned is notcalled. A clone is simply an exact copy of the original.

 

Cloneable 接口没有定义任何成员。它用来指明一个类可以逐位复制一个对象。如果你试图对一个没有实现cloneable接口的类调用clone()方法,一个CloneNotSupportedException 就会抛出。在复制时,被复制的对象的构造器并没有被调用。复制对象就是原来对象的拷贝。

 

Cloning is a potentially dangerous action, because it can cause unintended side effects. For example, if the object being cloned contains a reference variable called obRef, then when the clone is made, obRef in the clone will refer to the same object as does obRef in the original. If the clone makes a change to the contents of the object referred to by obRef, then it will be changed for the original object, too. Here is another example. If an object opens an I/O stream and is then cloned, two objects will be capable of operating on the same stream. Further, if one of these objects closes the stream, the other object might still attempt to write to it, causing an error.

 

复制是一种存在潜在危险的行为,因为它会引起一些意想不到的负作用。例如,如果被复制的对象包含一个名为 obRef 引用变量,在复制时,复制对象的 obRe和f 原来对象的 obRef 都会指向同一个对象。如果复制对象对 obRef 指向的对象的内容做出一些改变,对于原来对象来说,也就相当于它也被改变了。还有另一个例子,如果一个操作I/O流的对象被复制了,这两个对象都能对同一I/O流进行操作。进一步说,如果它们两个中的一个关闭了I/O流,而另一个对象可能试图对I/O流进行写操作,这就会引起错误。 

 

Because cloning can cause problems, clone( ) is declared as protected inside Object . This means that it must either be called from within a method defined by the class that implements Cloneable , or it must be explicitly overridden by that class so that it is public. Let's look at an example of each approach.

因为复制可以引起许多问题,clone()在object类中被声明为protected.这意味着,它要么在一个实现了cloneable接口的类中的某一方法里被调用,要么在明确的在那个类中的被重写,且被声明为public的。下面,我们来看一下每一种方法。 

 

 

The following program implements Cloneable and defines the method cloneTest( ) , which calls clone( ) in Object :

// Demonstrate the clone() method. 
class TestClone implements Cloneable { 
int a; 
double b; 
// This method calls Object's clone(). 
TestClone cloneTest() { 
try { 
// call clone in Object. 
return (TestClone) super.clone(); 
} catch(CloneNotSupportedException e) { 
System.out.println("Cloning not allowed."); 
return this; 


}

class CloneDemo { 
public static void main(String args[]) { 
TestClone x1 = new TestClone(); 
TestClone x2; 
x1.a = 10; 
x1.b = 20.98; 
x2 = x1.cloneTest(); // clone x1 
System.out.println("x1: " + x1.a + " " + x1.b); 
System.out.println("x2: " + x2.a + " " + x2.b); 

}

Here, the method cloneTest( ) calls clone( ) in Object and returns the result. Notice that the object returned by clone( )must be cast into its appropriate type (TestClone ). The following example overrides clone( ) so that it can be called from code outside of its class. To do this, its access specifier must be public , as shown here:

// Override the clone() method. 
class TestClone implements Cloneable { 
int a; 
double b; 
// clone() is now overridden and is public. 
public Object clone() { 
try { 
// call clone in Object. 
return super.clone(); 
} catch(CloneNotSupportedException e) { 
System.out.println("Cloning not allowed."); 
return this; 


}

class CloneDemo2 { 
public static void main(String args[]) { 
TestClone x1 = new TestClone(); 
TestClone x2; 
x1.a = 10; 
x1.b = 20.98; 
// here, clone() is called directly. 
x2 = (TestClone) x1.clone(); 
System.out.println("x1: " + x1.a + " " + x1.b); 
System.out.println("x2: " + x2.a + " " + x2.b); 

}

The side effects caused by cloning are sometimes difficult to see at first. It is easy to think that a class is safe for cloning when it actually is not. In general, you should not implement Cloneable for any class without good reason.

 

以上两个程序,运行一下,便于理解。

 

以下在补充两点:

1  It is what is known as a 'marker' interface . A marker interface has no methods or fields and serves only to identify the semantics of that interface. Another example is Serializable .

2  object.clone()可能产生a shallow copy()也可能产生a deep copy.

 

参考:http://www.codeguru.com/forum/showthread.php?s=&postid=660398#post660398

http://gabrielcjx.iteye.com/blog/445388

posted on 2012-07-20 10:35  Nolan  阅读(746)  评论(0编辑  收藏  举报