Java实现深克隆的两种方式
序列化和依次克隆各个可变的引用类型都可以实现深克隆,但是序列化的效率并不理想
下面是两种实现深克隆的实例,并且测试类对两种方法进行了对比:
1、重写clone方法使用父类中的clone()方法实现深克隆
package com.lk.B; public class Worker implements Cloneable{ private String name; private int age; public Worker(String name,int age){ this.name = name; this.age = age; } 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; } @Override public String toString() { // TODO Auto-generated method stub StringBuffer sb = new StringBuffer(); sb.append("姓名:"+name+","); sb.append("年龄:"+age+"\n"); return sb.toString(); } @Override protected Worker clone() { // TODO Auto-generated method stub Worker worker = null; try { worker = (Worker) super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return worker; } }
2、重写clone()方法使用序列化方法实现深克隆
package com.lk.B; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class Employee implements Cloneable,Serializable{ private static final long serialVersionUID = 1L; private String name; private int age; public Employee(String name,int age){ this.name = name; this.age = age; } 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; } @Override public String toString() { // TODO Auto-generated method stub StringBuffer sb = new StringBuffer(); sb.append("姓名:"+name+","); sb.append("年龄:"+age+"\n"); return sb.toString(); } @Override protected Employee clone() { // TODO Auto-generated method stub Employee employss = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); oos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); try { ObjectInputStream ois = new ObjectInputStream(bais); employss = (Employee) ois.readObject(); ois.close(); } catch (IOException | ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return employss; } }
两者的实现方式在上面已经列出来了
下面编写了一个测试类来测试两种方式的效率
package com.lk.B; import java.util.ArrayList; import java.util.List; public class Test3 { public static void main(String[] args) { List<Worker> workerList = new ArrayList<Worker>();//保存Worker对象 List<Employee> employeelist = new ArrayList<Employee>();//保存Employee对象 Worker worker = new Worker("阿坤", 21); Employee employee = new Employee("阿坤", 21); long time = System.currentTimeMillis();//取得系统当前时间 //保存10000个Worker对象复制品到列表 for(int i=0;i<10000;i++){ workerList.add(worker.clone()); } System.out.println("使用复制域的方式实现克隆所花费的时间:"+(System.currentTimeMillis()-time)+"ms"); time = System.currentTimeMillis();//取得系统当前时间 //保存10000个Employee对象复制品到列表 for(int i=0;i<10000;i++){ employeelist.add(employee.clone()); } System.out.println("使用复制域的方式实现克隆所花费的时间:"+(System.currentTimeMillis()-time)+"ms"); } }
运行结果:
/* 使用复制域的方式实现克隆所花费的时间:4ms 使用复制域的方式实现克隆所花费的时间:838ms */
可以看出,可以使用序列化和逐个复制引用类型域的方式完成深克隆,其中序列化的方式效率很低。