java对象克隆

1,238 阅读2分钟

1.浅拷贝

可以直接调用Object的clone方法,来完成对象自身的克隆,这个方法只能拷贝各个类的域值,如果如果这个类的属性中包含的是一种引用,克隆对象和原对象的相同域会引用同一个引用对象。

关于浅拷贝的子对象:

  • 原始对象与浅拷贝对象共享的子对象不可变的:不会有任何问题,比如子对象是属于String这样的不可变类型

  • 原始对象与浅拷贝共享的子对象可变:参考实现深拷贝

2.深拷贝

对于每个要拷贝的对象我们需要思考一下问题:

1)默认的clone方法是否满足需求

2)默认的clone方法是否能够通过调用可变子对象的clone得到修补

在实现clone时,相关类需要做的工作:

1.实现Cloneable接口,需要注意的是,Cloneable接口中并没有clone方法,实际上,这个接口中没有任何方法,它特别用来作为一个标记而实现

2.使用public重新定义clone

需要在clone方法尾部声明异常CloneNotSupportException,方法内部执行遇到的引用对象均需要实现clone方法,否则会抛出异常

代码如下

import java.util.*;

public class CloneTest
{
   public static void main(String[] args)
   {
      try
      {
         Employee original = new Employee("John Q. Public", 50000);
         original.setHireDay(2000, 1, 1);
         Employee copy = original.clone();
         copy.raiseSalary(10);
         copy.setHireDay(2002, 12, 31);
         System.out.println("original=" + original);
         System.out.println("copy=" + copy);
      }
      catch (CloneNotSupportedException e)
      {
         e.printStackTrace();
      }
   }
}

class Employee implements Cloneable
{
   public Employee(String n, double s)
   {
      name = n;
      salary = s;
      hireDay = new Date();
   }

   public Employee clone() throws CloneNotSupportedException
   {
      
      Employee cloned = (Employee) super.clone();
      cloned.hireDay = (Date) hireDay.clone();
      return cloned;
   }
   public void setHireDay(int year, int month, int day)
   {
      Date newHireDay = new GregorianCalendar(year, month - 1, day).getTime();
      
      // Example of instance field mutation
      hireDay.setTime(newHireDay.getTime());
   }

   public void raiseSalary(double byPercent)
   {
      double raise = salary * byPercent / 100;
      salary += raise;
   }

   public String toString()
   {
      return "Employee[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]";
   }

   private String name;
   private double salary;
   private Date hireDay;
}