Java Clone方法之懒人实现


在Java的Object类中定义了(protected)clone()方法,如果自己的类需要clone方法的话需要实现Cloneable接口,并重写clone()方法和将方法访问级别改为(public)。但是如果自己的类如果属性比较多,重写clone方法还是会花去不少时间,更重要的是以后增加或者删除属性的时候也要相应修改clone方法,总的来说还是比较麻烦的。

这里如果对性能不太计较的话,其实可以有一个简单快速的方法实现clone方法,就是使用Java语言的序列化功能来实现clone方法,如下:

以下是几个测试的Bean类

  1. import java.io.Serializable;   
  2. public class A implements Serializable {   
  3.     private static final long serialVersionUID = 1L;   
  4.     private String name;   
  5.     private B b;   
  6.     public String getName() {   
  7.         return name;   
  8.     }   
  9.     public void setName(String name) {   
  10.         this.name = name;   
  11.     }   
  12.     public B getB() {   
  13.         return b;   
  14.     }   
  15.     public void setB(B b) {   
  16.         this.b = b;   
  17.     }   
  18.     @Override  
  19.     public Object clone() {   
  20.         return CloneUtil.clone(this);   
  21.     }   
  22. }   
  23.   
  24. import java.io.Serializable;   
  25. public class B implements Serializable {   
  26.     private static final long serialVersionUID = 1L;   
  27.     private String name;   
  28.     private C c;   
  29.     public String getName() {   
  30.         return name;   
  31.     }   
  32.     public void setName(String name) {   
  33.         this.name = name;   
  34.     }   
  35.     public C getC() {   
  36.         return c;   
  37.     }   
  38.     public void setC(C c) {   
  39.         this.c = c;   
  40.     }   
  41.     @Override  
  42.     public Object clone() {   
  43.         return CloneUtil.clone(this);   
  44.     }   
  45. }   
  46.   
  47. import java.io.Serializable;   
  48. public class C implements Serializable, Cloneable {   
  49.     private static final long serialVersionUID = 1L;   
  50.     private String name;   
  51.     public String getName() {   
  52.         return name;   
  53.     }   
  54.     public void setName(String name) {   
  55.         this.name = name;   
  56.     }   
  57.     @Override  
  58.     public Object clone() {   
  59.         return CloneUtil.clone(this);   
  60.     }   
  61. }   

Clone工具类,这个类负责通过序列化和反序列化做到对一个对象的clone

  1. import java.io.*;   
  2. public class CloneUtil {   
  3.     public static Object clone(Object obj) {   
  4.         Object anotherObj = null;   
  5.         byte[] bytes;   
  6.         ByteArrayOutputStream baos = new ByteArrayOutputStream();   
  7.         ObjectOutputStream oos = null;   
  8.         try {   
  9.             oos = new ObjectOutputStream(baos);   
  10.             oos.writeObject(obj);   
  11.             bytes = baos.toByteArray();   
  12.         } catch(IOException ex) {   
  13.             throw new RuntimeException(ex.getMessage(), ex);   
  14.         } finally {   
  15.             if (oos != null) {   
  16.                 try {   
  17.                     oos.close();   
  18.                 } catch (IOException e) {   
  19.                     // ignore me   
  20.                 }   
  21.             }   
  22.         }   
  23.         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);   
  24.         ObjectInputStream ois = null;   
  25.         try {   
  26.             ois = new ObjectInputStream(bais);   
  27.             anotherObj = ois.readObject();   
  28.         } catch(IOException ex) {   
  29.             throw new RuntimeException(ex.getMessage(), ex);   
  30.         } catch(ClassNotFoundException ex) {   
  31.             throw new RuntimeException(ex.getMessage(), ex);   
  32.         } finally {   
  33.             if (ois != null) {   
  34.                 try {   
  35.                     ois.close();   
  36.                 } catch (IOException e) {   
  37.                     // ignore me   
  38.                 }   
  39.             }   
  40.         }   
  41.         return anotherObj;   
  42.     }   
  43. }   

测试类

  1. public class Test {   
  2.     public static void main(String[] args) throws Exception {   
  3.         A a = new A();   
  4.         B b = new B();   
  5.         C c = new C();   
  6.         c.setName("ccc");   
  7.         b.setName("bbb");   
  8.         b.setC(c);   
  9.         a.setName("aaa");   
  10.         a.setB(b);   
  11.         System.out.println("a: " + a);   
  12.         System.out.println("a: " + a.getName());   
  13.         System.out.println("a: " + a.getB().getName());   
  14.         System.out.println("a: " + a.getB().getC().getName());   
  15.         A anotherA = (A)a.clone();   
  16.         System.out.println("anotherA: " + anotherA);   
  17.         System.out.println("anotherA: " + anotherA.getName());   
  18.         System.out.println("anotherA: " + anotherA.getB().getName());   
  19.         System.out.println("anotherA: " + anotherA.getB().getC().getName());   
  20.         System.out.println("=== change properties of a ===");   
  21.            
  22.         a.setName("aaaaa");   
  23.         a.getB().setName("bbbbb");   
  24.         a.getB().getC().setName("ccccc");   
  25.         System.out.println("a: " + a);   
  26.         System.out.println("a: " + a.getName());   
  27.         System.out.println("a: " + a.getB().getName());   
  28.         System.out.println("a: " + a.getB().getC().getName());   
  29.         System.out.println("anotherA: " + anotherA);   
  30.         System.out.println("anotherA: " + anotherA.getName());   
  31.         System.out.println("anotherA: " + anotherA.getB().getName());   
  32.         System.out.println("anotherA: " + anotherA.getB().getC().getName());   
  33.         System.out.println("=== change properties of anotherA ===");   
  34.            
  35.         anotherA.setName("aaaa");   
  36.         anotherA.getB().setName("bbbb");   
  37.         anotherA.getB().getC().setName("cccc");   
  38.         System.out.println("a: " + a);   
  39.         System.out.println("a: " + a.getName());   
  40.         System.out.println("a: " + a.getB().getName());   
  41.         System.out.println("a: " + a.getB().getC().getName());   
  42.         System.out.println("anotherA: " + anotherA);   
  43.         System.out.println("anotherA: " + anotherA.getName());   
  44.         System.out.println("anotherA: " + anotherA.getB().getName());   
  45.         System.out.println("anotherA: " + anotherA.getB().getC().getName());   
  46.     }   
  47. }   

运行测试类可以看到结果。这里通过代码可以看出这种实现还是有一些限制的:

1. 自己的bean必须实现Serializable接口;

2. 由于这种实现使用了序列化,所以性能不是很好,所以如果对象太多,不建议使用;

3. 由于在序列化的过程中没有将对象序列化到文件中,而是保留在了内存数组中,所以如果对象太大的话,会造成比较大的内存使用,需要注意。

相关内容