Java对象的浅克隆和深克隆

来源:互联网 发布:ubuntu ports 源 编辑:程序博客网 时间:2024/05/16 14:39
为什么需要克隆
     在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在Java语言中,用简单的赋值语句是不能满足这种需求的,要满足这种需求有很多途径。
 
    克隆的实现方式

      一、浅度克隆
    
      浅度克隆对于要克隆的对象,对于其基本数据类型的属性,复制一份给新产生的对象,对于非基本数据类型的属性,仅仅复制一份引用给新产生的对象,即新产生的对象和原始对象中的非基本数据类型的属性都指向的是同一个对象。

      浅度克隆步骤:
      1、实现java.lang.Cloneable接口
         要clone的类为什么还要实现Cloneable接口呢?Cloneable接口是一个标识接口,不包含任何方法的!这个标识仅仅是针对Object类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object的 clone()方法(也就是调用了super.Clone()方法),那么Object的clone()方法就会抛出 CloneNotSupportedException异常。
 
     2、重写java.lang.Object.clone()方法
       JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。
 
      观察一下Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为什么要用Object中clone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能。Object类中的clone()还是一个protected属性的方法,重写之后要把clone()方法的属性设置为public
 
Object类中clone()方法产生的效果是:先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内容。对基本数据类型,这样的操作是没有问题的,但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象。
 
Java代码实例:
public class Product implements Cloneable {   
    private String name;   
  
    public Object clone() {   
        try {   
            return super.clone();   
        } catch (CloneNotSupportedException e) {   
            return null;   
        }   
    }   
}  
 
 
   二、深度克隆
     
     在浅度克隆的基础上,对于要克隆的对象中的非基本数据类型的属性对应的类,也实现克隆,这样对于非基本数据类型的属性,复制的不是一份引用,即新产生的对象和原始对象中的非基本数据类型的属性指向的不是同一个对象
 
      深度克隆步骤:
      要克隆的类和类中所有非基本数据类型的属性对应的类
        1、都实现java.lang.Cloneable接口
        2、都重写java.lang.Object.clone()方法
 
Java代码实例:
public class Attribute implements Cloneable {   
    private String no;   
       
    public Object clone() {   
        try {   
            return super.clone();   
        } catch (CloneNotSupportedException e) {   
            return null;   
        }   
    }   
}   
  
public class Product implements Cloneable {   
    private String name;   
       
    private Attribute attribute;   
  
    public Object clone() {   
        try {   
            return super.clone();   
        } catch (CloneNotSupportedException e) {   
            return null;   
        }   
    }   
}   
 
 
      三、使用对象序列化和反序列化实现深度克隆
        所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象。
 
对象的序列化还有另一个容易被大家忽略的功能就是对象复制(Clone),Java中通过Clone机制可以复制大部分的对象,但是众所周知,Clone有深度Clone和浅度Clone,如果你的对象非常非常复杂,并且想实现深层 Clone,如果使用序列化,不会超过10行代码就可以解决。
 
虽然Java的序列化非常简单、强大,但是要用好,还有很多地方需要注意。比如曾经序列化了一个对象,可由于某种原因,该类做了一点点改动,然后重新被编译,那么这时反序列化刚才的对象,将会出现异常。 你可以通过添加serialVersionUID属性来解决这个问题(在Java序列化与反序列化学习(二):序列化接口说明 的标题三中有此说明)。如果你的类是个单例(Singleton)类,虽然我们多线程下的并发问题来控制单例,但是,是否允许用户通过序列化机制或者克隆来复制该类,如果不允许你需要谨慎对待该类的实现(让此类不用实现Serializable接口或Externalizable接口和Cloneable接口就行了)
  
Java代码实例:
public class Attribute {   
    private String no;   
}   
  
public class Product {   
    private String name;   
       
    private Attribute attribute;   
  
    public Product clone() {   
        ByteArrayOutputStream byteOut = null;   
        ObjectOutputStream objOut = null;   
        ByteArrayInputStream byteIn = null;   
        ObjectInputStream objIn = null;   
           
        try {   
// 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
            byteOut = new ByteArrayOutputStream();    
            objOut = new ObjectOutputStream(byteOut);    
            objOut.writeObject(this);   
  // 将流序列化成对象
            byteIn = new ByteArrayInputStream(byteOut.toByteArray());   
            objIn = new ObjectInputStream(byteIn);   
               
            return (ContretePrototype) objIn.readObject();   
        } catch (IOException e) {   
            throw new RuntimeException("Clone Object failed in IO.",e);      
        } catch (ClassNotFoundException e) {   
            throw new RuntimeException("Class not found.",e);      
        } finally{   
            try{   
                byteIn = null;   
                byteOut = null;   
                if(objOut != null) objOut.close();      
                if(objIn != null) objIn.close();      
            }catch(IOException e){      
            }      
        }   
    }   
或者:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public static <T extends Serializable> T copy(T input) {  
  2.     ByteArrayOutputStream baos = null;  
  3.     ObjectOutputStream oos = null;  
  4.     ByteArrayInputStream bis = null;  
  5.     ObjectInputStream ois = null;  
  6.     try {  
  7.         baos = new ByteArrayOutputStream();  
  8.         oos = new ObjectOutputStream(baos);  
  9.         oos.writeObject(input);  
  10.         oos.flush();  
  11.   
  12.         byte[] bytes = baos.toByteArray();  
  13.         bis = new ByteArrayInputStream(bytes);  
  14.         ois = new ObjectInputStream(bis);  
  15.         Object result = ois.readObject();  
  16.         return (T) result;  
  17.     } catch (IOException e) {  
  18.         throw new IllegalArgumentException("Object can't be copied", e);  
  19.     } catch (ClassNotFoundException e) {  
  20.         throw new IllegalArgumentException("Unable to reconstruct serialized object due to invalid class definition", e);  
  21.     } finally {  
  22.         closeQuietly(oos);  
  23.         closeQuietly(baos);  
  24.         closeQuietly(bis);  
  25.         closeQuietly(ois);  
  26.     }  
  27. }  

也可以用json等其他序列化技术实现深度复制;

#########################注意######################
Bean复制的几种框架中(Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier)都是相当于克隆中的浅克隆。
1)spring包和Apache中的 BeanUtils     采用反射实现
    Spring: void copyProperties(Object source, Object target,String[] ignoreProperties)
    Apache:void  copyProperties(Object dest, Object orig)
2)cglib包中的  Beancopier   采用动态字节码实现
   cglib: BeanCopier create(Class source, Class target,boolean useConverter)
   例如:
          BeanCopier copier =BeanCopier.create(stuSource.getClass(), stuTarget.getClass(), false);
          copier.copy(stuSource, stuTarget, null);

公司内部对用到的bean属性复制做了下性能分析:
cglib   BeanCopier   15ms

Spring  BeanUtil      4031ms

apache BeanUtils      18514ms.
#########################注意######################

clone和BeanUtils.copyProperties对比:

Cloning is done by you. If the instance which you trying clone contains reference of another instance you have to write cloning code to that one too. What if the instances contains chain of references to other instances? So if you do cloning by yourself, there are chances that you might miss a small detail.

BeanUtils.copyProperties on otherhand take care of everything by itself. It reduces your effort.


java中对象的克隆

克隆是完全复制另一个物体,在Java中,意味着创建一个和原对象有相似状态的对象。clone()方法就提供了这个功能,在这篇文章中,我们将探索java 克隆的一些最重要的方面。这篇文章是mini guides的一个部分

详细解释克隆

克隆是创建原对象的一个复制,字典上的意思是“精确的复制”。默认情况下,java的克隆是一个字段一个字段的复制。例如:对象类调用的clone()方法,对将要复制的类的结构并没有一个清晰的了解。那么当克隆的时候,JVM将会做以下的事情:
1、如果这个类只有原生数据类型成员,那么一个原对象的完全复制会被创建,新对象的引用将会被返回。
2、如果这个对象包含类类型,那么只有这些对象的引用会被复制,因此克隆对象和原对象的成员的引用指向同一个对象。
除了默认的情况,你可以重写这些行为并指定自己的方式,这需要覆盖clone()方法,让我们看看是怎么样克隆的?

java克隆的构造

支持克隆对象的每一种语言都有自己的克隆规则,java也是。在java中,如果一个类需要支持克隆,那么它需要做两件事情。
1、你必须实现Cloneable接口。
2、你必须在类中重写clone()方法
在java文档中给出了下边的解释:
[java] view plain copy
  1. /* 
  2. Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object. 
  3. The general intent is that, for any object x, the expression: 
  4. 1) x.clone() != x will be true 
  5. 2) x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements. 
  6. 3) x.clone().equals(x) will be true, this is not an absolute requirement. 
  7. */  
  8. protected native Object  clone() throws CloneNotSupportedException;  

1、第一个语句保证了克隆对象会有独立的内存地址分配
2、第二个语句表明原生对象和克隆对象的需要具有相同的类型,但是不是强制的
3、第三个语句表明原生对象和克隆对象使用equals()时应该是相等的,但是也是不是强制的。
让我们看看实际的代码:
我们的第一个类Employee有三个属性 Id,name和department
[java] view plain copy
  1. public class Employee implements Cloneable{  
  2.    
  3.     private int empoyeeId;  
  4.     private String employeeName;  
  5.     private Department department;  
  6.    
  7.     public Employee(int id, String name, Department dept)  
  8.     {  
  9.         this.empoyeeId = id;  
  10.         this.employeeName = name;  
  11.         this.department = dept;  
  12.     }  
  13.     @Override  
  14.     protected Object clone() throws CloneNotSupportedException {  
  15.         return super.clone();  
  16.     }  
  17.        
  18.     //Accessor/mutators methods will go there  
  19. }  

我们的Department类有两个属性,id和name
[java] view plain copy
  1. public class Department  
  2. {  
  3.     private int id;  
  4.     private String name;  
  5.    
  6.     public Department(int id, String name)  
  7.     {  
  8.         this.id = id;  
  9.         this.name = name;  
  10.     }  
  11.     //Accessor/mutators methods will go there  
  12. }  

所以如果我们想克隆Employee类,那么我们需要做像下边的事情:
[java] view plain copy
  1. public class TestCloning {  
  2.    
  3.     public static void main(String[] args) throws CloneNotSupportedException  
  4.     {  
  5.         Department dept = new Department(1"Human Resource");  
  6.         Employee original = new Employee(1"Admin", dept);  
  7.         //Lets create a clone of original object  
  8.         Employee cloned = (Employee) original.clone();  
  9.         //Let verify using employee id, if cloning actually workded  
  10.         System.out.println(cloned.getEmpoyeeId());  
  11.    
  12.         //Verify JDK's rules  
  13.    
  14.         //Must be true and objects must have different memory addresses  
  15.         System.out.println(original != cloned);  
  16.    
  17.         //As we are returning same class; so it should be true  
  18.         System.out.println(original.getClass() == cloned.getClass());  
  19.    
  20.         //Default equals method checks for refernces so it should be false. If we want to make it true,  
  21.         //we need to override equals method in Employee class.  
  22.         System.out.println(original.equals(cloned));  
  23.     }  
  24. }  
  25. Output:  
  26. 1  
  27. true  
  28. true  
  29. false  

我们已经成功克隆了Employee对象,但是,记住我们已经有同一个对象的两个引用了,现在这连个都会改变在不同的应用中改变状态。
[java] view plain copy
  1. public class TestCloning {  
  2.    
  3.     public static void main(String[] args) throws CloneNotSupportedException {  
  4.         Department hr = new Department(1"Human Resource");  
  5.         Employee original = new Employee(1"Admin", hr);  
  6.         Employee cloned = (Employee) original.clone();  
  7.    
  8.         //Let change the department name in cloned object and we will verify in original object  
  9.         cloned.getDepartment().setName("Finance");  
  10.    
  11.         System.out.println(original.getDepartment().getName());  
  12.     }  
  13. }  
  14. Output: Finance  

克隆对象和原生对象的值都改变了,如果允许这么做可能会引起系统的损毁,任何人都可以克隆你的对象,并改变你对象的引用,这将会是灾难性的,那么怎么阻止它呢?
我们可以使用深度克隆和复制构造来解决这个问题,我们会在这篇文章的后边学习

浅克隆

这是java中默认的实现的方式,复写clone方法时,如果你没有克隆所有的对象类型(不是原生类型),那么你就是浅克隆。所有的上边的例子都是浅克隆,因为我们没有在Employee类的clone方法中克隆Department对象,现在我们来介绍深克隆。

深克隆

在大多数情况下,这是最想要的行为:我们克隆的对象的行为的改变不会影响到原生对象的值。
我们来看一下在我们的例子中如何来做:
[java] view plain copy
  1. //Modified clone() method in Employee class  
  2. @Override  
  3. protected Object clone() throws CloneNotSupportedException {  
  4.     Employee cloned = (Employee)super.clone();  
  5.     cloned.setDepartment((Department)cloned.getDepartment().clone());  
  6.     return cloned;  
  7. }  

我修改了Employee中的clone方法并在Department类中的clone方法中增加了如下代码:
[java] view plain copy
  1. //Defined clone method in Department class.  
  2. @Override  
  3. protected Object clone() throws CloneNotSupportedException {  
  4.     return super.clone();  
  5. }  

现在我们来测试一下:

[java] view plain copy
  1. public class TestCloning {  
  2.     public static void main(String[] args) throws CloneNotSupportedException {  
  3.         Department hr = new Department(1"Human Resource");  
  4.         Employee original = new Employee(1"Admin", hr);  
  5.         Employee cloned = (Employee) original.clone();  
  6.    
  7.         //Let change the department name in cloned object and we will verify in original object  
  8.         cloned.getDepartment().setName("Finance");  
  9.    
  10.         System.out.println(original.getDepartment().getName());  
  11.     }  
  12. }  
  13. Output:  
  14. Human Resource  

这里克隆对象的改变并没有改变原生对象的值

那么深克隆需要满足下边的情况:

1、没有必要单独复制primitive

2、原生对象中的所有类成员都必须支持clone方法,在原生对象的成员类中都要调用super.clone()方法

3、如果类成员变量不支持clone,那么它必须创建那个成员类的新的实例,并把它的属性一个一个的复制到新的对象中去,新的类成员对象在clone对象中被设置。

使用复制构造

复制构造是类中特殊的构造方法,它需要把自己的类型当做参数,所以当你传递一个类的实例给复构造时,这个构造会返回参数给出的类型的实例,我们来看下边这个例子:
[java] view plain copy
  1. public class PointOne {  
  2.     private Integer x;  
  3.     private Integer y;  
  4.    
  5.     public PointOne(PointOne point){  
  6.         this.x = point.x;  
  7.         this.y = point.y;  
  8.     }  
  9. }  

这个方法看起来很简单,但是当继承的时候就不是这样了。当你定义一个类继承上边这个类,你需要定义相似的构造方法,在子类中,你需要复制子类的属性并且传递给父类的构造传递参数
[java] view plain copy
  1. public class PointTwo extends PointOne{  
  2.     private Integer z;  
  3.    
  4.     public PointTwo(PointTwo point){  
  5.         super(point); //Call Super class constructor here  
  6.         this.z = point.z;  
  7.     }  
  8. }  

这样就可以了吗?不行,问题是继承是运行时的行为,所以在我们的例子中,如果一些类传递PointTwo的实例在PointOne的构造中,你将会得到PointOne的实例。我们来看下边的代码:
[java] view plain copy
  1. class Test  
  2. {  
  3.     public static void main(String[] args)  
  4.     {  
  5.         PointOne one = new PointOne(1,2);  
  6.         PointTwo two = new PointTwo(1,2,3);  
  7.    
  8.         PointOne clone1 = new PointOne(one);  
  9.         PointOne clone2 = new PointOne(two);  
  10.    
  11.         //Let check for class types  
  12.         System.out.println(clone1.getClass());  
  13.         System.out.println(clone2.getClass());  
  14.     }  
  15. }  
  16. Output:  
  17. class corejava.cloning.PointOne  
  18. class corejava.cloning.PointOne  

创建复制构造的另一种方式是利用静态工厂方法,他们把类的类型作为参数,使用类的其他构造方法创建实例。那么这些工厂方法将会复制所有的状态数据到新的类实例中去。
[java] view plain copy
  1. public class PointOne implements Cloneable{  
  2.     private Integer x;  
  3.     private Integer y;  
  4.    
  5.     public PointOne(Integer x, Integer y)  
  6.     {  
  7.         this.x = x;  
  8.         this.y = y;  
  9.     }  
  10.    
  11.     public PointOne copyPoint(PointOne point) throws CloneNotSupportedException  
  12.     {  
  13.         if(!(point instanceof Cloneable))  
  14.         {  
  15.             throw new CloneNotSupportedException("Invalid cloning");  
  16.         }  
  17.         //Can do multiple other things here  
  18.         return new PointOne(point.x, point.y);  
  19.     }  
  20. }  

序列化的克隆

这是深克隆的另一种简单的方式,这种方法,你只需要序列化需要克隆的对象并反序列化就可以了。显然需要克隆的对象应该实现序列化接口。在进行下一步之前,我需要提醒的是它不能被轻易的使用,首先序列化有高昂的代价,它可能是clone方法的上百倍,第二并非所有的对象都是可以序列化的,第三类序列化并不是一个可以依赖的,它并不可靠。
[java] view plain copy
  1. @SuppressWarnings("unchecked")  
  2. public static  T clone(T t) throws Exception {  
  3.     //Check if T is instance of Serializeble other throw CloneNotSupportedException  
  4.     ByteArrayOutputStream bos = new ByteArrayOutputStream();  
  5.    
  6.     //Serialize it  
  7.     serializeToOutputStream(t, bos);  
  8.     byte[] bytes = bos.toByteArray();  
  9.     ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));  
  10.    
  11.     //Deserialize it and return the new instance  
  12.     return (T)ois.readObject();  
  13. }  

使用apche Commons克隆

apche commons也实现了深克隆的功能,如果你感兴趣可以查看文档说明,下边这是使用的一个简单的例子
[java] view plain copy
  1. SomeObject cloned = org.apache.commons.lang.SerializationUtils.clone(someObject);  

最佳实践

1、当你不知道你是否可以调用clone方法的时候,你可以使用 class is instance of Cloneable来检查:
[java] view plain copy
  1. if(obj1 instanceof Cloneable){  
  2.     obj2 = obj1.clone();  
  3. }  
  4.    
  5. //Dont do this. Cloneabe dont have any methods  
  6. obj2 = (Cloneable)obj1.clone();  

2、被克隆的对象中没有构造方法被调用,你应该负责所有的成员变量被恰当的设置,如果你在构造方法中跟踪对象的调用,那么这也是一个增加计数器的地方

原文地址:http://howtodoinjava.com/2012/11/08/a-guide-to-object-cloning-in-java/


java对象 深度克隆(不实现Cloneable接口)和浅度克隆

为什么需要克隆:

在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在Java语言中,用简单的赋值语句是不能满足这种需求的,要满足这种需求有很多途径。

 

克隆的实现方式

一、浅度克隆

对于要克隆的对象,对于其基本数据类型的属性,复制一份给新产生的对象,对于非基本数据类型的属性,仅仅复制一份引用给新产生的对象,即新产生的对象和原始对象中的非基本数据类型的属性都指向的是同一个对象

1、实现java.lang.Cloneable接口

要clone的类为什么还要实现Cloneable接口呢?Cloneable接口是一个标识接口,不包含任何方法的!这个标识仅仅是针对Object类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object的 clone()方法(也就是调用了super.Clone()方法),那么Object的clone()方法就会抛出 CloneNotSupportedException异常。

 

2、重写java.lang.Object.clone()方法

JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。

 

观察一下Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为什么要用Object中clone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能。Object类中的clone()还是一个protected属性的方法,重写之后要把clone()方法的属性设置为public。

 

Object类中clone()方法产生的效果是:先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内容。对基本数据类型,这样的操作是没有问题的,但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象。

 

 

 

Java代码

  1. public class Product implements Cloneable {   

  2.     private String name;   

  3.   

  4.     public Object clone() {   

  5.         try {   

  6.             return super.clone();   

  7.         } catch (CloneNotSupportedException e) {   

  8.             return null;   

  9.         }   

  10.     }   

  11. }  

 

 

 

 

二、深度克隆

在浅度克隆的基础上,对于要克隆的对象中的非基本数据类型的属性对应的类,也实现克隆,这样对于非基本数据类型的属性,复制的不是一份引用,即新产生的对象和原始对象中的非基本数据类型的属性指向的不是同一个对象

 

要克隆的类和类中所有非基本数据类型的属性对应的类

1、都实现java.lang.Cloneable接口

 

2、都重写java.lang.Object.clone()方法

 

 

 

Java代码

  1. public class Attribute implements Cloneable {   

  2.     private String no;   

  3.        

  4.     public Object clone() {   

  5.         try {   

  6.             return super.clone();   

  7.         } catch (CloneNotSupportedException e) {   

  8.             return null;   

  9.         }   

  10.     }   

  11. }   

  12.   

  13. public class Product implements Cloneable {   

  14.     private String name;   

  15.        

  16.     private Attribute attribute;   

  17.   

  18.     public Object clone() {   

  19.         try {   

  20.             return super.clone();   

  21.         } catch (CloneNotSupportedException e) {   

  22.             return null;   

  23.         }   

  24.     }   

  25. }  

  

 

 

 

三、使用对象序列化和反序列化实现深度克隆

所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象。

 

对象的序列化还有另一个容易被大家忽略的功能就是对象复制(Clone),Java中通过Clone机制可以复制大部分的对象,但是众所周知,Clone有深度Clone和浅度Clone,如果你的对象非常非常复杂,并且想实现深层 Clone,如果使用序列化,不会超过10行代码就可以解决。

 

虽然Java的序列化非常简单、强大,但是要用好,还有很多地方需要注意。比如曾经序列化了一个对象,可由于某种原因,该类做了一点点改动,然后重新被编译,那么这时反序列化刚才的对象,将会出现异常。 你可以通过添加serialVersionUID属性来解决这个问题。如果你的类是个单例(Singleton)类,是否允许用户通过序列化机制复制该类,如果不允许你需要谨慎对待该类的实现。

 

 

 

Java代码

  1. public class Attribute {   

  2.     private String no;   

  3. }   

  4.   

  5. public class Product {   

  6.     private String name;   

  7.        

  8.     private Attribute attribute;   

  9.   

  10.     public Product clone() {   

  11.         ByteArrayOutputStream byteOut = null;   

  12.         ObjectOutputStream objOut = null;   

  13.         ByteArrayInputStream byteIn = null;   

  14.         ObjectInputStream objIn = null;   

  15.            

  16.         try {   

  17.             byteOut = new ByteArrayOutputStream();    

  18.             objOut = new ObjectOutputStream(byteOut);    

  19.             objOut.writeObject(prototype);   

  20.   

  21.             byteIn = new ByteArrayInputStream(byteOut.toByteArray());   

  22.             objIn = new ObjectInputStream(byteIn);   

  23.                

  24.             return (ContretePrototype) objIn.readObject();   

  25.         } catch (IOException e) {   

  26.             throw new RuntimeException("Clone Object failed in IO.",e);      

  27.         } catch (ClassNotFoundException e) {   

  28.             throw new RuntimeException("Class not found.",e);      

  29.         } finally{   

  30.             try{   

  31.                 byteIn = null;   

  32.                 byteOut = null;   

  33.                 if(objOut != null) objOut.close();      

  34.                 if(objIn != null) objIn.close();      

  35.             }catch(IOException e){      

  36.             }      

  37.         }   

  38.     }   

  39.  




原创粉丝点击