对象克隆----Cloneable接口
2018-11-18 本文已影响0人
爱做梦的严重精神病患者
默认的clone方法是Object的一个protected方法,不能在其他类中直接调用,需要实现Cloneable接口。默认的克隆操作是“浅拷贝”,并没有克隆原对象中引用的其他对象。
如果对象中的所有数据域都是数值或其他基本类型,拷贝这些域没有任何问题。但是如果对象包含其他对象的引用,拷贝域就会得到相同的其他对象的另一个引用,这样一来原对象和克隆的对象仍然共享一些信息。
如果原对象和浅克隆对象共享的对象域是不可变的(属于不可变类,例:String类),那么这种共享就是安全的。或者在对象的生命周期中,对象域一直包含不变的常量,没有更改器会改变它,也没有方法会生成它的引用,同样也是安全的。
不过,通常对象域都是可变的,必须重新定义clone方法来建立一个深度拷贝,同时克隆所有对象域。
对于每一个类,使用clone需要:
- 实现Cloneable接口;
- 重新定义clone方法,并指定public访问修饰符。
默认的浅度拷贝(克隆):实现Cloneable接口,将clone重新定义为public,再调用super.clone()。
public class Employee implements Cloneable {
public Employee clone() throws CloneNotSupportedException {
return (Employee) super.clone();
}
}
深度拷贝(克隆):克隆所有对象域。
public class Employee implements Cloneable {
private String name;
private double salary;
private Date hireDay;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
hireDay = new Date();
}
public Employee clone() throws CloneNotSupportedException {
Employee cloned = (Employee) super.clone();
//Date类已实现Cloneable接口
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();
hireDay.setTime(newHireDay.getTime());
}
public void raiseSalary(double byPercent) {
double raise = salary * byPercent / 100;
salary += raise;
}
}
注意子类的克隆。例如,一旦为Employee类定义了clone方法,任何人都可以利用它来克隆Manager对象(Manager extends Employee)。Employee.clone()不能百分百完成工作,这要取决于Manager类的域。
不能保证子类的实现者一定会修正clone方法,让它正常工作。