测试类:
Player类,包含name level 和 weapon 三个成员
public class Player implements Cloneable {
private static final long serialVersionUID = -75L;
private String name;
private int level;
private Weapon weapon;
public Player(){
name = "sam";
level = 10;
weapon = new Weapon();
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public Weapon getWeapon() {
return weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
@Override
public String toString() {
return "Player{" +
"name='" + name + '\'' +
", level=" + level +
", weapon=" + weapon.getName() +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Player o = (Player) super.clone();
return o;
}
}
Weapon:包含 name 一个成员
public class Weapon implements Cloneable {
private String name;
public Weapon(String name) {
this.name = name;
}
public Weapon() {
this.name = "AK74";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
1. 直接赋值,引用传递,C2 = C1 ,不会为复制过去的实例分配空间,C2这个引用直接指向C1的实例,C1中有成员改变,C2也同样改变,很好理解。
这里r1赋值给r2,之后改变r1的成员,再次打印r2
Player r1 = new Player(); Player r2 = r1; r1.setName("tom"); r1.setLevel(20); r1.getWeapon().setName("HK416"); System.out.println(r2);
输出结果:可见r2的值已经随着r1更新。
2. 浅拷贝,使用Object.clone()方法 ,C1复制到新实例中(堆上分配空间),C2指向这个新实例。
复制的过程中:如果字段是值类型的,那么对该字段执行复制。如果该字段是引用类型的话,则复制引用但不复制引用的对象。
首先Player和Weapon都已实现Cloneable接口的clone方法,执行clone,之后改变r1的成员,再次打印r2内容
Player r1 = new Player(); Player r2 = (Player) r1.clone(); r1.setName("tom"); r1.setLevel(20); r1.getWeapon().setName("HK416"); System.out.println(r2);
输出结果:r2中,字段为值类型的部分则被复制成功,随着r1更新,并未变化。但weapon字段却更新为HK416了,说明r2中的weapon还是指向了r1的weapon
3. 深拷贝,同样使用Object.clone()方法 ,复制引用并同时复制引用的对象重构Player中的clone方法,将引用类型成员也clone过去。@Override protected Object clone() throws CloneNotSupportedException { Player o = (Player) super.clone(); o.weapon = (Weapon) weapon.clone(); return o; }
输出结果:可见此时r2完全未受到r1成员变更的影响,通俗的理解,r2现在完全与r1脱离了。
4. 深拷贝的另一种实现:实现 Serializable接口,序列化,写入文件再读出,这个很好理解,读出来,是一个新的实例了,肯定是深拷贝。不再赘述。