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;
}